zoukankan      html  css  js  c++  java
  • Android系列之Fragment(二)Fragment的生命周期和返回栈

    Android系列之Fragment(二)Fragment的生命周期和返回栈 - Android - 次元立方网 - 电脑知识与技术互动交流平台

    【正文】

    上一章节中(Android系列之Fragment(一)----Fragment加载到Activity当中),我们对Fragment的生命周期进行了简单介绍,这一章节将对生命周期和返回栈进行详细介绍。

    一、Fragment的生命周期初探:

    因为Fragment必须嵌入在Acitivity中使用,所以Fragment的生命周期和它所在的Activity是密切相关的。

    如果Activity是暂停状态,其中所有的Fragment都是暂停状态;如果Activity是stopped状态,这个Activity中所有的Fragment都不能被启动;如果Activity被销毁,那么它其中的所有Fragment都会被销毁。

    但是,当Activity在活动状态,可以独立控制Fragment的状态,比如加上或者移除Fragment。

    当这样进行fragment transaction(转换)的时候,可以把fragment放入Activity的back stack中,这样用户就可以进行返回操作。

    使用Fragment时,需要继承Fragment或者Fragment的子类(DialogFragment, ListFragment, PreferenceFragment, WebViewFragment),所以Fragment的代码看起来和Activity的类似。

    每当创建一个Fragment时,首先添加以下三个回调方法:

    onCreate():系统在创建Fragment的时候调用这个方法,这里应该初始化相关的组件,一些即便是被暂停或者被停止时依然需要保留的东西。 onCreateView():当第一次绘制Fragment的UI时系统调用这个方法,该方法将返回一个View,如果Fragment不提供UI也可以返回null。注意,如果继承自ListFragment,onCreateView()默认的实现会返回一个ListView,所以不用自己实现。 onPause():当用户离开Fragment时第一个调用这个方法,需要提交一些变化,因为用户很可能不再返回来。

    将Fragment加载到Activity当中有两种方式:

    方式一:添加Fragment到Activity的布局文件当中 方式二:在Activity的代码中动态添加Fragment(荐)

    第一种方式虽然简单但灵活性不够。添加Fragment到Activity的布局文件当中,就等同于将Fragment及其视图与activity的视图绑定在一起,且在activity的生命周期过程中,无法切换fragment视图。

    第二种方式比较复杂,但也是唯一一种可以在运行时控制fragment的方式(加载、移除、替换)。

    二、Fragment的生命周期详解:

    先来看一下官方文档的图片吧:

    我们再把Activity的生命周期和Fragment的生命周期对比一下,就清楚很多了:

    我们还是在实例中来看一下Fragment的生命周期吧。

    【实例】在MainActivity中加载一个Fragment:(完整版代码如下)

    我们所创建的Fragment的布局文件fragment01.xml的代码如下:

    01.<?xml version='1.0' encoding='utf-8'?>
    02.<LinearLayout xmlns:android='http://schemas.android.com/apk/res/android'
    03.    android:layout_width='match_parent'
    04.    android:layout_height='match_parent'
    05.    android:orientation='vertical' >
    06. 
    07.    <RatingBar
    08.        android:id='@+id/ratingBar1'
    09.        android:layout_width='wrap_content'
    10.        android:layout_height='wrap_content' />
    11. 
    12.    <Button
    13.        android:id='@+id/button1'
    14.        android:layout_width='wrap_content'
    15.        android:layout_height='wrap_content'
    16.        android:text='Button' />
    17. 
    18.</LinearLayout>

    MyFragment.java代码如下:(注意生命周期中每个方法的作用)

    001.  1 package com.example.m01_fragmentlifecycle;
    002.  2
    003.  3 import android.app.Activity;
    004.  4 import android.app.Fragment;
    005.  5 import android.os.Bundle;
    006.  6 import android.util.Log;
    007.  7 import android.view.LayoutInflater;
    008.  8 import android.view.View;
    009.  9 import android.view.ViewGroup;
    010. 10
    011. 11 public class MyFragment extends Fragment {
    012. 12     private final String TAG = 'MyFragment';
    013. 13    
    014. 14     //获得activity的传递的值
    015. 15     @Override
    016. 16     public void onAttach(Activity activity) {
    017. 17         // TODO Auto-generated method stub
    018. 18         super.onAttach(activity);
    019. 19         Log.i(TAG, '--MyFragment->>onAttach');
    020. 20     }
    021. 21
    022. 22     //实例化成员变量
    023. 23     @Override
    024. 24     public void onCreate(Bundle savedInstanceState) {
    025. 25         // TODO Auto-generated method stub
    026. 26         super.onCreate(savedInstanceState);
    027. 27         Log.i(TAG, '--MyFragment->>onCreate');
    028. 28     }
    029. 29
    030. 30     //给当前的fragment绘制UI布局,可以使用线程更新UI
    031. 31     @Override
    032. 32     public View onCreateView(LayoutInflater inflater, ViewGroup container,
    033. 33             Bundle savedInstanceState) {
    034. 34         Log.i(TAG, '--MyFragment->>onCreateView');
    035. 35         View view = inflater.inflate(R.layout.fragment01, null);
    036. 36         // TODO Auto-generated method stub
    037. 37         return view;
    038. 38     }
    039. 39
    040. 40     //表示activity执行oncreate方法完成了的时候会调用此方法
    041. 41     @Override
    042. 42     public void onActivityCreated(Bundle savedInstanceState) {
    043. 43         // TODO Auto-generated method stub
    044. 44         super.onActivityCreated(savedInstanceState);
    045. 45         Log.i(TAG, '--MyFragment->>onActivityCreated');
    046. 46     }
    047. 47
    048. 48     //和activity一致
    049. 49     @Override
    050. 50     public void onStart() {
    051. 51         // TODO Auto-generated method stub
    052. 52         super.onStart();
    053. 53         Log.i(TAG, '--MyFragment->>onStart');
    054. 54     }
    055. 55
    056. 56     //和activity一致
    057. 57     @Override
    058. 58     public void onResume() {
    059. 59         // TODO Auto-generated method stub
    060. 60         super.onResume();
    061. 61         Log.i(TAG, '--MyFragment->>onResume');
    062. 62     }
    063. 63
    064. 64     //和activity一致
    065. 65     @Override
    066. 66     public void onPause() {
    067. 67         // TODO Auto-generated method stub
    068. 68         super.onPause();
    069. 69         Log.i(TAG, '--MyFragment->>onPause');
    070. 70     }
    071. 71
    072. 72     //和activity一致
    073. 73     @Override
    074. 74     public void onStop() {
    075. 75         // TODO Auto-generated method stub
    076. 76         super.onStop();
    077. 77         Log.i(TAG, '--MyFragment->>onStop');
    078. 78     }
    079. 79
    080. 80     //表示fragment销毁相关联的UI布局
    081. 81     @Override
    082. 82     public void onDestroyView() {
    083. 83         // TODO Auto-generated method stub
    084. 84         super.onDestroyView();
    085. 85         Log.i(TAG, '--MyFragment->>onDestroyView');
    086. 86     }
    087. 87
    088. 88     //销毁fragment对象
    089. 89     @Override
    090. 90     public void onDestroy() {
    091. 91         // TODO Auto-generated method stub
    092. 92         super.onDestroy();
    093. 93         Log.i(TAG, '--MyFragment->>onDestroy');
    094. 94     }
    095. 95
    096. 96     //脱离activity
    097. 97     @Override
    098. 98     public void onDetach() {
    099. 99         // TODO Auto-generated method stub
    100.100         super.onDetach();
    101.101         Log.i(TAG, '--MyFragment->>onDetach');
    102.102     }
    103.103 }

    activity_main.xml的代码如下:

    01.<LinearLayout xmlns:android='http://schemas.android.com/apk/res/android'
    02.    xmlns:tools='http://schemas.android.com/tools'
    03.    android:layout_width='match_parent'
    04.    android:layout_height='match_parent'
    05.    android:orientation='horizontal'
    06.    tools:context='.MainActivity' >
    07. 
    08.    <LinearLayout
    09.        android:id='@+id/line'
    10.        android:layout_width='wrap_content'
    11.        android:layout_height='match_parent'
    12.        android:orientation='vertical' >
    13.    </LinearLayout>
    14.     
    15.</LinearLayout>

    MainActivity.java的代码如下:

    01.1 package com.example.m01_fragmentlifecycle;
    02. 2
    03. 3 import android.os.Bundle;
    04. 4 import android.app.Activity;
    05. 5 import android.app.FragmentManager;
    06. 6 import android.app.FragmentTransaction;
    07. 7 import android.util.Log;
    08. 8 import android.view.Menu;
    09. 9
    10.10 public class MainActivity extends Activity {
    11.11     private final String TAG = 'MainActivity';
    12.12     private FragmentManager manager;
    13.13     private FragmentTransaction transaction;
    14.14
    15.15     @Override
    16.16     protected void onCreate(Bundle savedInstanceState) {
    17.17         super.onCreate(savedInstanceState);
    18.18         setContentView(R.layout.activity_main);
    19.19         manager = getFragmentManager();
    20.20         transaction = manager.beginTransaction();
    21.21         MyFragment fragment = new MyFragment();
    22.22         transaction.add(R.id.line, fragment);
    23.23         transaction.commit();
    24.24         Log.i(TAG, '--MainActivity->>onCreate');
    25.25     }
    26.26
    27.27     @Override
    28.28     protected void onStart() {
    29.29         // TODO Auto-generated method stub
    30.30         super.onStart();
    31.31         Log.i(TAG, '--MainActivity->>onStart');
    32.32     }
    33.33
    34.34     @Override
    35.35     protected void onResume() {
    36.36         // TODO Auto-generated method stub
    37.37         super.onResume();
    38.38         Log.i(TAG, '--MainActivity->>onResume');
    39.39     }
    40.40
    41.41     @Override
    42.42     protected void onPause() {
    43.43         // TODO Auto-generated method stub
    44.44         super.onPause();
    45.45         Log.i(TAG, '--MainActivity->>onPause');
    46.46     }
    47.47
    48.48     @Override
    49.49     protected void onStop() {
    50.50         // TODO Auto-generated method stub
    51.51         super.onStop();
    52.52         Log.i(TAG, '--MainActivity->>onStop');
    53.53     }
    54.54    
    55.55     @Override
    56.56     protected void onRestart() {
    57.57         // TODO Auto-generated method stub
    58.58         super.onRestart();
    59.59         Log.i(TAG, '--MainActivity->>onRestart');
    60.60     }
    61.61     @Override
    62.62     protected void onDestroy() {
    63.63         // TODO Auto-generated method stub
    64.64         super.onDestroy();
    65.65         Log.i(TAG, '--MainActivity->>onDestroy');
    66.66     }
    67.67
    68.68     @Override
    69.69     public boolean onCreateOptionsMenu(Menu menu) {
    70.70         // Inflate the menu; this adds items to the action bar if it is present.
    71.71         getMenuInflater().inflate(R.menu.main, menu);
    72.72         return true;
    73.73     }
    74.74 }

    可以看到,上面的代码在每个生命周期的方法里都打印了日志,然后我们来运行一下程序,可以看到打印日志如下:

    初次加载:(分成两部分来看)

    点击一下home键(或接入电话),打印日志如下:

    重新进入进入程序(或电话结束),打印日志如下:

    点击back键退出程序,打印日志如下:

    通过上面的日志,我们能够看出,Fragment和Activity的生命周期太相似了。只是有几个Activity中没有的新方法,需要重点介绍一下:

    onAttach方法:Fragment和Activity建立关联的时候调用(获得activity的传递的值) onCreateView方法:为Fragment创建视图(加载布局)时调用(给当前的fragment绘制UI布局,可以使用线程更新UI) onActivityCreated方法:当Activity中的onCreate方法执行完后调用(表示activity执行oncreate方法完成了的时候会调用此方法) onDestroyView方法:Fragment中的布局被移除时调用(表示fragment销毁相关联的UI布局) onDetach方法:Fragment和Activity解除关联的时候调用(脱离activity)

    三、Fragment返回栈的管理:

    将Fragment添加到返回栈中:

    假设现在我们有两个Fragment:Fragment01和Fragment02,我们现在从Fragment01的界面跳到Fragment02,然后按Back键,发现程序是直接退出了,而不是返回到Fragment01。如果现在想实现以下功能:从Fragment01的界面跳到Fragment02,然后按Back键,会返回到Fragment01。这个功能该怎么实现呢?这其实就利用到了返回栈的知识。

    其实很简单,FragmentTransaction中提供了一个addToBackStack()方法,可以将一个事务添加到返回栈中。

    我们先回顾一下之前动态加载Fragment的代码,然后在此基础之上,增加一行代码就可以将Fragment添加到返回栈中:(即第07行代码)

    01.1                 //步骤一:添加一个FragmentTransaction的实例
    02.2                 FragmentManager fragmentManager =getFragmentManager();
    03.3                 FragmentTransaction transaction = fragmentManager.beginTransaction();
    04.4                 //步骤二:用add()方法加上Fragment的对象
    05.5                 RightFragment rightFragment = new RightFragment();
    06.6                 transaction.add(R.id.right, rightFragment);
    07.<strong>7                 transaction.addToBackStack(null);
    08.</strong>8                 //步骤三:调用commit()方法使得FragmentTransaction实例的改变生效
    09.9                 transaction.commit(); 

    第07行代码:我们在事务提交之前调用了FragmentTransaction的addToBackStack()方法,它可以接受一个名字用于描述返回栈的状态,,一般传入null即可。

    【实例】现在通过代码来实现以下界面(下面的图片为程序运行时加载的首页),并且把每一个Fragment都加入到返回栈当中去,然后观察其生命周期的变化。完整代码如下:

    首先新建工程文件m01_Fragment04,然后开始我们的代码之旅:

    我们先把右侧的四个Fragment建起来吧:

    Fragment01.java主要部分的代码如下:

    01.1 package com.example.m01_fragment04;
    02. 2
    03. 3 import android.app.Fragment;
    04. 4 import android.os.Bundle;
    05. 5 import android.view.LayoutInflater;
    06. 6 import android.view.View;
    07. 7 import android.view.ViewGroup;
    08. 8
    09. 9 public class Fragment01 extends Fragment {
    10.10    
    11.11     @Override
    12.12     public void onCreate(Bundle savedInstanceState) {
    13.13         super.onCreate(savedInstanceState);
    14.14     }
    15.15    
    16.16     @Override
    17.17     public View onCreateView(LayoutInflater inflater, ViewGroup container,
    18.18             Bundle savedInstanceState) {
    19.19         View view = inflater.inflate(R.layout.f1, null);
    20.20         return view;
    21.21     }
    22.22     @Override
    23.23     public void onPause() {
    24.24         super.onPause();
    25.25     }
    26.26 }

    为避免啰嗦,这里就不把Fragment01生命周期中的其他函数罗列出来了,我们只要知道在实际代码中这些函数都是加了的。

    Fragment01的布局文件f1.xml的代码如下:

    01.<?xml version='1.0' encoding='utf-8'?>
    02.<LinearLayout xmlns:android='http://schemas.android.com/apk/res/android'
    03.    android:layout_width='match_parent'
    04.    android:layout_height='match_parent'
    05.    android:orientation='vertical' >
    06. 
    07.    <TextView
    08.        android:id='@+id/textView1'
    09.        android:layout_width='wrap_content'
    10.        android:layout_height='wrap_content'
    11.        android:text='加载图片' />
    12. 
    13.</LinearLayout>

    然后依次新建出Fragment02、Fragment03、Fragment04的java代码和布局文件。

    MainActivity的布局文件activity_main.xml代码如下:

    01.<LinearLayout xmlns:android='http://schemas.android.com/apk/res/android'
    02.    xmlns:tools='http://schemas.android.com/tools'
    03.    android:layout_width='match_parent'
    04.    android:layout_height='match_parent'
    05.    tools:context='.MainActivity' >
    06. 
    07.    <LinearLayout
    08.        android:id='@+id/left'
    09.        android:layout_width='wrap_content'
    10.        android:layout_height='match_parent'
    11.        android:background='#CCCCCC'
    12.        android:orientation='vertical' >
    13. 
    14.        <Button
    15.            android:id='@+id/button1'
    16.            android:layout_width='wrap_content'
    17.            android:layout_height='wrap_content'
    18.            android:text='加载图片' />
    19. 
    20.        <Button
    21.            android:id='@+id/button2'
    22.            android:layout_width='wrap_content'
    23.            android:layout_height='wrap_content'
    24.            android:text='海报管理' />
    25. 
    26.        <Button
    27.            android:id='@+id/button3'
    28.            android:layout_width='wrap_content'
    29.            android:layout_height='wrap_content'
    30.            android:text='照片管理' />
    31.    
    32.        <Button
    33.            android:id='@+id/button4'
    34.            android:layout_width='wrap_content'
    35.            android:layout_height='wrap_content'
    36.            android:text='新闻管理' />       
    37.         
    38.    </LinearLayout>
    39. 
    40.    <LinearLayout
    41.        android:id='@+id/right'      
    42.        android:layout_width='0dp'
    43.        android:layout_height='match_parent'
    44.        android:layout_weight='1'
    45.        android:orientation='vertical' >
    46.    </LinearLayout>
    47. 
    48.</LinearLayout>

    其中,第一个LinearLayout表示左侧的按钮,第二个LinearLayout留给右边的Fragment。

    MainActivity.java的代码如下:

    01.1 package com.example.m01_fragment04;
    02. 2
    03. 3 import android.os.Bundle;
    04. 4 import android.app.Activity;
    05. 5 import android.app.FragmentManager;
    06. 6 import android.app.FragmentTransaction;
    07. 7 import android.view.Menu;
    08. 8 import android.view.View;
    09. 9 import android.view.View.OnClickListener;
    10.10 import android.widget.Button;
    11.11
    12.12 public class MainActivity extends Activity  implements OnClickListener{
    13.13
    14.14     private FragmentManager manager;
    15.15     private FragmentTransaction transaction;
    16.16     private Button button1,button2,button3,button4;
    17.17    
    18.18     @Override
    19.19     protected void onCreate(Bundle savedInstanceState) {
    20.20         super.onCreate(savedInstanceState);
    21.21         setContentView(R.layout.activity_main);
    22.22        
    23.23     manager = getFragmentManager();
    24.24         button1 = (Button)this.findViewById(R.id.button1);
    25.25         button1.setOnClickListener(this);
    26.26         button2 = (Button)this.findViewById(R.id.button2);
    27.27         button2.setOnClickListener(this);
    28.28         button3 = (Button)this.findViewById(R.id.button3);
    29.29         button3.setOnClickListener(this);
    30.30         button4 = (Button)this.findViewById(R.id.button4);
    31.31         button4.setOnClickListener(this);
    32.32        
    33.33     }
    34.34
    35.35     @Override
    36.36     public boolean onCreateOptionsMenu(Menu menu) {
    37.37         // Inflate the menu; this adds items to the action bar if it is present.
    38.38         getMenuInflater().inflate(R.menu.main, menu);
    39.39         return true;
    40.40     }
    41.41
    42.42     //通过点击不同的按钮,跳转到不同的Fragment
    43.43     @Override
    44.44     public void onClick(View v) {
    45.45         // TODO Auto-generated method stub
    46.<strong>46         transaction = manager.beginTransaction();
    47.</strong>47         switch (v.getId()) {
    48.48         case R.id.button1:
    49.49             Fragment01 fragment01 = new Fragment01();
    50.50             transaction.replace(R.id.right, fragment01, 'fragment01');
    51.51             transaction.addToBackStack('fragment01');// 添加到Activity管理的回退栈中。
    52.52             break;
    53.53
    54.54         case R.id.button2:
    55.55             Fragment02 fragment02 = new Fragment02();
    56.56             transaction.replace(R.id.right, fragment02, 'fragment02');
    57.57             transaction.addToBackStack('fragment02');// 添加到Activity管理的回退栈中。
    58.58             break;
    59.59
    60.60         case R.id.button3:
    61.61             Fragment03 fragment03 = new Fragment03();
    62.62             transaction.replace(R.id.right, fragment03, 'fragment03');
    63.63             transaction.addToBackStack('fragment03');// 添加到Activity管理的回退栈中。
    64.64             break;
    65.65
    66.66         case R.id.button4:
    67.67             Fragment04 fragment04 = new Fragment04();
    68.68             transaction.replace(R.id.right, fragment04, 'fragment04');
    69.69             transaction.addToBackStack('fragment04');// 添加到Activity管理的回退栈中。
    70.70             break;
    71.71         }
    72.<strong>72 </strong><strong>        transaction.commit();   </strong>    
    73.73     }
    74.74    
    75.75 }

    上当代码中,通过点击不同的按钮,就能跳到对应的Fragment,而这四个Fragment都已经加入到了返回栈当中。运行程序之后,也是这样的。

    注意第46行和第72行,transaction = manager.beginTransaction()意味着开始,transaction.commit()意味着结束。

    我们就其中的fragment01和fragment02来讨论一下他们的生命周期的变化:

    运行程序后,界面如下,没有任何fragment被加载:

    点击左侧第一个按钮,加载fragment01:

    点击左侧第二个按钮,加载fragment02(此时fragment01被替换,并被压到了栈当中):

    注:如果fragment01在替换的时候没有被压到栈中,那就会被销毁,在执行完onDestroyView()方法后,会继续执行onDestroy()和onDetach()方法。

    按Back键,fragment01重新返回到屏幕:(fragment02被销毁)

    再按Back键,fragment01被销毁:

     注:Fragment的返回栈由Activity管理;而Activity的返回栈由系统管理。

    【工程文件】

    链接:http://pan.baidu.com/s/1i3DrYmx

    密码:uh46



    文章来源:http://www.cnblogs.com/smyhvae/p/3983234.html

  • 相关阅读:
    了解 NoSQL 的必读资料
    关于什么时候用assert(断言)的思考
    这次见到了一些大侠
    NetBeans 时事通讯(刊号 # 87 Jan 12, 2010)
    动态链接库dll,静态链接库lib, 导入库lib
    新女性十得 写得了代码,查得出异常
    记录系统乱谈
    新女性十得 写得了代码,查得出异常
    fullpage.js禁止滚动
    RunningMapReduceExampleTFIDF hadoopclusternet This document describes how to run the TFIDF MapReduce example against ascii books. This project is for those who wants to experiment hadoop as a skunkworks in a small cluster (110 nodes) Google Pro
  • 原文地址:https://www.cnblogs.com/seven1979/p/4345126.html
Copyright © 2011-2022 走看看