• 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

  • 相关阅读:
    java练习按要求编写Java程序:
    java基础练习编写2个接口
    java基础练习 给定一个正整数m,统计m的位数,分别打印每一位数字,再按照逆序打印出各位数字。
    java泛型(转)
    Java程序设计上机作业1
    java基础练习继承
    java冒泡排序
    java基础作业
    java 加深了解
    java基本代码的解释
  • 原文地址:https://www.cnblogs.com/seven1979/p/4345126.html
Copyright © 2020-2023  润新知