前言
上一篇blog(处女男学Android(八)---Fragment初体验之实现Tab导航)记录了fragment的基本概念和基本的使用方法,本篇将逐步深入记录关于fragment的几个重要知识点,包括:fragment的生命周期、fragment的back stack(回退栈)等等,下面就从fragmeng的生命周期说起。
一、fragment生命周期概述
与Activity类似,Fragment作为一个容器也必定有它自己的生命周期,如果能熟练掌握一个fragment从创建到销毁过程中的每一个方法,以及它们的调用时机,那么我们将可以更好的去管理一个fragment,比如我们可以根据需求,在不同的状态中做一些有用的事情,下面看一下官方给出的流程图:
![Fragment进阶篇之Fragment生命周期和回退栈_第1张图片](http://img.e-com-net.com/image/info8/cfd4b8610bae49b68a619bdada4c23f7.jpg)
下面对这11个方法做一下大致的解释。
onAttach(Activity activity)
---Called when the fragment has been associated with the activity (the Activity
is passed in here).
---当该fragment被添加到Activity时回调,该方法只会被调用一次。
onCreat(Bundle savedInstanceState)
---创建fragment时被回调。该方法只会调用一次。
onCreatView(LayoutInflater inflater,ViewGroup container,Bundle savedInstanceState)
---Called to create the view hierarchy associated with the fragment.
---每次创建、绘制该fragment的View组件时回调该方法,fragment将会显示该方法的View组件。
onActivityCreated(Bundle savedInstanceState)
---Called when the activity's onCreate()
method has returned.
---当fragment所在的Activity被创建完成后调用该方法。
onStart()
---启动fragment时被回调。
onResume()
---恢复fragment时被回调,onStart()方法后一定会回调onResume()方法。
onPause()
---暂停fragment时被回调。
onStop()
---停止fragment时被回调。
onDestroyView()
---Called when the view hierarchy associated with the fragment is being removed.
---销毁该fragment所包含的View组件时调用。
onDestory()
---销毁fragment时被回调,该方法只会被调用一次。
onDetach()
---Called when the fragment is being disassociated from the activity.
---当该fragment从Activity中被删除、被替换完成时回调该方法,onDestory()方法后一定会回调onDetach()方法。该方法只会被调用一次。
其实学习生命周期最好的方法还是在程序中通过打印语句来观察每个阶段的状态和顺序,下面就通过一个简单的例子来看一下一个fragment完整的生命周期的过程。
二、一个简单的例子
Layout代码(fragment.xml):
- xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical" >
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="30dp"
- android:background="#FFCC00"
- android:gravity="center"
- android:text="TextView2 in Fragment" />
-
- <ListView
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:entries="@array/heros" >
- ListView>
-
- LinearLayout>
MyFragment代码:
- package com.example.fragmentlifecycledemo;
-
- import android.app.Activity;
- import android.app.Fragment;
- import android.os.Bundle;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.ViewGroup;
-
- public class MyFragment extends Fragment {
-
- private final String TAG = "--MyFragment--> ";
-
- @Override
- public void onAttach(Activity activity) {
- // TODO Auto-generated method stub
- System.out.println(TAG + "onAttach");
- super.onAttach(activity);
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- // TODO Auto-generated method stub
- System.out.println(TAG + "onCreate");
- super.onCreate(savedInstanceState);
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- // TODO Auto-generated method stub
- System.out.println(TAG + "onCreateView");
- View view = inflater.inflate(R.layout.fragment, null);
- return view;
- }
-
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
- // TODO Auto-generated method stub
- System.out.println(TAG + "onActivityCreated");
- super.onActivityCreated(savedInstanceState);
- }
-
- @Override
- public void onStart() {
- // TODO Auto-generated method stub
- System.out.println(TAG + "onStart");
- super.onStart();
- }
-
- @Override
- public void onResume() {
- // TODO Auto-generated method stub
- System.out.println(TAG + "onResume");
- super.onResume();
- }
-
- @Override
- public void onPause() {
- // TODO Auto-generated method stub
- System.out.println(TAG + "onPause");
- super.onPause();
- }
-
- @Override
- public void onStop() {
- // TODO Auto-generated method stub
- System.out.println(TAG + "onStop");
- super.onStop();
- }
-
- @Override
- public void onDestroyView() {
- // TODO Auto-generated method stub
- System.out.println(TAG + "onDestroyView");
- super.onDestroyView();
- }
-
- @Override
- public void onDestroy() {
- // TODO Auto-generated method stub
- System.out.println(TAG + "onDestroy");
- super.onDestroy();
- }
-
- @Override
- public void onDetach() {
- // TODO Auto-generated method stub
- System.out.println(TAG + "onDetach");
- super.onDetach();
- }
-
- }
可以看到上面的代码是fragment类和它所要加载的布局文件,并在fragment中声明了生命周期中的每个方法以及打印语句。fragment的布局文件很简单,只有一个TextView和一个固定内容的ListView。下面看看Activity的代码和布局文件。
Layout代码(activity_main.xml):
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- tools:context="com.example.fragmentlifecycledemo.MainActivity" >
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
- android:background="#FFDDFF"
- android:gravity="center"
- android:height="0dp"
- android:text="TextView1 in MainActivity" />
-
- <FrameLayout
- android:id="@+id/lt_frame"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="3" >
- FrameLayout>
-
- LinearLayout>
MainActivity代码:
- package com.example.fragmentlifecycledemo;
-
- import android.app.Activity;
- import android.app.FragmentManager;
- import android.app.FragmentTransaction;
- import android.os.Bundle;
-
- public class MainActivity extends Activity {
-
- private final String TAG = "--MainActivity---> ";
-
- private FragmentManager manager;
- private FragmentTransaction transaction;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- System.out.println(TAG + " onCreate");
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- manager = getFragmentManager();
- transaction = manager.beginTransaction();
- transaction.add(R.id.lt_frame, new MyFragment());
- transaction.commit();
- }
-
- @Override
- protected void onStart() {
-
- System.out.println(TAG + " onStart");
- super.onStart();
- }
-
- @Override
- protected void onResume() {
-
- System.out.println(TAG + " onResume");
- super.onResume();
- }
-
- @Override
- protected void onPause() {
-
- System.out.println(TAG + " onPause");
- super.onPause();
- }
-
- @Override
- protected void onStop() {
-
- System.out.println(TAG + " onStop");
- super.onStop();
- }
-
- @Override
- protected void onDestroy() {
-
- System.out.println(TAG + " onDestroy");
- super.onDestroy();
- }
-
- }
类似的,同样声明了Activity生命周期中的所有方法以及打印语句,并且当Activity创建时将MyFragment动态添加到activity_main.xml中的FrameLayout布局文件里,可以看到这个布局文件是空的,所以它就相当于用来装fragment的容器了。
下面看一下运行效果和LogCat控制台的打印结果:
![Fragment进阶篇之Fragment生命周期和回退栈_第2张图片](http://img.e-com-net.com/image/info8/97ece9f5439444b487306dc04bf92a8d.gif)
可以看到fragment正常被加载到了Activity的FrameLayout中了,那么现在看看LogCat:
![Fragment进阶篇之Fragment生命周期和回退栈_第3张图片](http://img.e-com-net.com/image/info8/3f602de4b0494e3792677941145d1297.jpg)
可以看到首先是Activity被创建,紧接着fragment与Activity绑定(onAttach),然后fragment被创建(onCreat),fragment的视图被创建(onCreatView),fragment所在的Activity的onCreate()方法已经被返回(onActivityCreated),最后Actvity启动,fragment启动,Activity处于运行状态,fragment处于运行状态。
当我点返回键之后,再看一下运行效果和LogCat控制台的打印结果:
![Fragment进阶篇之Fragment生命周期和回退栈_第4张图片](http://img.e-com-net.com/image/info8/43f3109847a54edf9a8bad1893c9c70d.gif)
可以看到已经点击返回键退出应用了,那么现在看看LogCat:
![Fragment进阶篇之Fragment生命周期和回退栈_第5张图片](http://img.e-com-net.com/image/info8/96ea2f4844044dcd8ba4bda1bc33b92e.jpg)
可以看到退出的时候,首先是fragment暂停、Activity暂停,然后fragment停止、Activity停止,然后销毁fragment的视图(onDestoryView,与onCreatView相对应)、与之前绑定的Activity解除关联(onDetach,与onAttach相对应),最后是Activity的销毁。
通过上面的分析我们可以证实:
fragment的生命周期确实是伴随着Activity的生命周期变化的,并且它是依附于Activity的。先创建Activity,再创建fragment,先销毁fragment,再销毁Activity,这种层次结构的设计也是非常合理的,而且和“栈”的结构有些相似,即:“后进先出”。下面将记录fragment的另一个重要的概念,即“回退栈(back stack)”。
三、回退栈(back stack)
其实回退栈很简单,fragment的回退栈和Activity的回退栈是类似的,就是如果把一个fragment事务添加到回退栈,那么点返回按钮的时候也就可以看到上一次保存的fragment,不至于直接退出Activity。也就是通过这个方法来将fragment事务添加到回退栈的:
- transaction.addToBackStack(String name);
下面通过例子来看看回退栈的应用,顺便再说说我在学习回退栈的同时学到的其它相关知识,对于我来说还是很有意义的。需求是这样的:同样是上面的英雄列表,当我点击ListView的某一项时,下面的fragment就替换成一个新的界面,这个界面有一个文本框,需要输入当前项的英雄名称,还有一个确定按钮,点击确定时,如果输入的和当前项的英雄名一致,就弹出土司提示正确并附加英雄名,如果输入的和当前项的英雄名不一致,也弹出土司提示错误,但不显示英雄名。重点是,我在二级界面点击返回的时候,要跳回ListView的界面,下面贴上我重构后的代码。
Layout代码(f1.xml-->二级界面的布局文件):
- xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical" >
-
- <TextView
- android:id="@+id/tv_textView_f1"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="0.7"
- android:background="#F7F7F7"
- android:gravity="center"
- android:text="我是HERO,我的名字是?"
- android:textSize="20sp" />
-
- <EditText
- android:id="@+id/et_editText_e1"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="0.15"
- android:inputType="textPersonName"
- android:hint="请输入英雄名" />
-
- <Button
- android:id="@+id/btn_button_b1"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="0.15"
- android:text="确定" />
-
- LinearLayout>
MyFragment代码(只重构了onCreatView方法):
- package com.example.fragmentlifecycledemo;
-
- import android.app.Fragment;
- import android.os.Bundle;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.view.ViewGroup;
- import android.widget.Button;
- import android.widget.EditText;
- import android.widget.Toast;
-
- public class MySubFragment extends Fragment implements OnClickListener {
- private Button mButton;
- private EditText editText1;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
-
- super.onCreate(savedInstanceState);
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
-
- View v = inflater.inflate(R.layout.f1, container, false);
- editText1 = (EditText) v.findViewById(R.id.et_editText_e1);
- mButton = (Button) v.findViewById(R.id.btn_button_b1);
- mButton.setOnClickListener(this);
- return v;
- }
-
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
-
- super.onActivityCreated(savedInstanceState);
- }
-
- @Override
- public void onPause() {
-
- super.onPause();
- }
-
- @Override
- public void onClick(View v) {
-
- String name = (String) getArguments().getCharSequence("heroName");
-
- String input = editText1.getText().toString();
- if (name.equals(input)) {
- Toast.makeText(getActivity(), "回答正确!我的名字是:" + name,
- Toast.LENGTH_LONG).show();
- } else {
- Toast.makeText(getActivity(), "回答错误!我不告诉你我的名字!", Toast.LENGTH_LONG)
- .show();
- }
- }
- }
下面再看一下重构后的运行效果:
可以看到点击Item跳转之后,再点击返回按钮又可以成功返回到ListView,而不会直接退出程序,这就是fragment回退栈的作用了,其实在重构这些代码时我思考更多的是如何将ListView中Item的值传到二级fragment中,之前的做法是:直接在MyFragment的onItemClick方法中得到Item的View和二级Fragment的View,通过xxx.getText(“”+xxx.setText)这种方式去做,结果一直报错,后来整理了思路,结合上面学习的生命周期,我理解了fragment的View都是在各自的onCreatView方法中完成的,这样把代码分开才最终解决了问题。
四、结合回退栈再看生命周期
加了回退栈之后,我们有必要看看点击返回按钮之后生命周期的变化,下面就贴上从桌面进入APP、点击一项Item、点击返回、再点击返回退出APP的完整的生命周期输出信息。
![Fragment进阶篇之Fragment生命周期和回退栈_第6张图片](http://img.e-com-net.com/image/info8/3d4f777927aa4994994b0bca11ae4427.jpg)
注意红色方框一级Fragment跳到二级Fragment的时候只调用的onDestoryView(),并没有调用onDestory,而点击返回的时候,自然就直接调用onCreatView,这也正是回退栈的作用了。
五、总结
其实我想重构这个例子只是测试一下回退栈,但设计需求的同时又想把ListView中每个Item项的文本信息传到跳转之后的二级fragment中,所以我先理清思路,发现问题所在,并仔细思考了如何传递数据、在哪里保存数据又应该在哪里读取数据,最后完成需求。这样在无形之中又学到了更多,我也明白了学一个知识的时候不能仅仅满足于表面,往往在你发掘需求的同时就又会发现一些更有意思的事情,本篇先记录到这里,以后还要继续加油!更加努力!
前言
上一篇blog(处女男学Android(八)---Fragment初体验之实现Tab导航)记录了fragment的基本概念和基本的使用方法,本篇将逐步深入记录关于fragment的几个重要知识点,包括:fragment的生命周期、fragment的back stack(回退栈)等等,下面就从fragmeng的生命周期说起。
一、fragment生命周期概述
与Activity类似,Fragment作为一个容器也必定有它自己的生命周期,如果能熟练掌握一个fragment从创建到销毁过程中的每一个方法,以及它们的调用时机,那么我们将可以更好的去管理一个fragment,比如我们可以根据需求,在不同的状态中做一些有用的事情,下面看一下官方给出的流程图:
![Fragment进阶篇之Fragment生命周期和回退栈_第7张图片](http://img.e-com-net.com/image/info8/cfd4b8610bae49b68a619bdada4c23f7.jpg)
下面对这11个方法做一下大致的解释。
onAttach(Activity activity)
---Called when the fragment has been associated with the activity (the Activity
is passed in here).
---当该fragment被添加到Activity时回调,该方法只会被调用一次。
onCreat(Bundle savedInstanceState)
---创建fragment时被回调。该方法只会调用一次。
onCreatView(LayoutInflater inflater,ViewGroup container,Bundle savedInstanceState)
---Called to create the view hierarchy associated with the fragment.
---每次创建、绘制该fragment的View组件时回调该方法,fragment将会显示该方法的View组件。
onActivityCreated(Bundle savedInstanceState)
---Called when the activity's onCreate()
method has returned.
---当fragment所在的Activity被创建完成后调用该方法。
onStart()
---启动fragment时被回调。
onResume()
---恢复fragment时被回调,onStart()方法后一定会回调onResume()方法。
onPause()
---暂停fragment时被回调。
onStop()
---停止fragment时被回调。
onDestroyView()
---Called when the view hierarchy associated with the fragment is being removed.
---销毁该fragment所包含的View组件时调用。
onDestory()
---销毁fragment时被回调,该方法只会被调用一次。
onDetach()
---Called when the fragment is being disassociated from the activity.
---当该fragment从Activity中被删除、被替换完成时回调该方法,onDestory()方法后一定会回调onDetach()方法。该方法只会被调用一次。
其实学习生命周期最好的方法还是在程序中通过打印语句来观察每个阶段的状态和顺序,下面就通过一个简单的例子来看一下一个fragment完整的生命周期的过程。
二、一个简单的例子
Layout代码(fragment.xml):
- xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical" >
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="30dp"
- android:background="#FFCC00"
- android:gravity="center"
- android:text="TextView2 in Fragment" />
-
- <ListView
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:entries="@array/heros" >
- ListView>
-
- LinearLayout>
MyFragment代码:
- package com.example.fragmentlifecycledemo;
-
- import android.app.Activity;
- import android.app.Fragment;
- import android.os.Bundle;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.ViewGroup;
-
- public class MyFragment extends Fragment {
-
- private final String TAG = "--MyFragment--> ";
-
- @Override
- public void onAttach(Activity activity) {
- // TODO Auto-generated method stub
- System.out.println(TAG + "onAttach");
- super.onAttach(activity);
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- // TODO Auto-generated method stub
- System.out.println(TAG + "onCreate");
- super.onCreate(savedInstanceState);
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- // TODO Auto-generated method stub
- System.out.println(TAG + "onCreateView");
- View view = inflater.inflate(R.layout.fragment, null);
- return view;
- }
-
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
- // TODO Auto-generated method stub
- System.out.println(TAG + "onActivityCreated");
- super.onActivityCreated(savedInstanceState);
- }
-
- @Override
- public void onStart() {
- // TODO Auto-generated method stub
- System.out.println(TAG + "onStart");
- super.onStart();
- }
-
- @Override
- public void onResume() {
- // TODO Auto-generated method stub
- System.out.println(TAG + "onResume");
- super.onResume();
- }
-
- @Override
- public void onPause() {
- // TODO Auto-generated method stub
- System.out.println(TAG + "onPause");
- super.onPause();
- }
-
- @Override
- public void onStop() {
- // TODO Auto-generated method stub
- System.out.println(TAG + "onStop");
- super.onStop();
- }
-
- @Override
- public void onDestroyView() {
- // TODO Auto-generated method stub
- System.out.println(TAG + "onDestroyView");
- super.onDestroyView();
- }
-
- @Override
- public void onDestroy() {
- // TODO Auto-generated method stub
- System.out.println(TAG + "onDestroy");
- super.onDestroy();
- }
-
- @Override
- public void onDetach() {
- // TODO Auto-generated method stub
- System.out.println(TAG + "onDetach");
- super.onDetach();
- }
-
- }
可以看到上面的代码是fragment类和它所要加载的布局文件,并在fragment中声明了生命周期中的每个方法以及打印语句。fragment的布局文件很简单,只有一个TextView和一个固定内容的ListView。下面看看Activity的代码和布局文件。
Layout代码(activity_main.xml):
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- tools:context="com.example.fragmentlifecycledemo.MainActivity" >
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
- android:background="#FFDDFF"
- android:gravity="center"
- android:height="0dp"
- android:text="TextView1 in MainActivity" />
-
- <FrameLayout
- android:id="@+id/lt_frame"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="3" >
- FrameLayout>
-
- LinearLayout>
MainActivity代码:
- package com.example.fragmentlifecycledemo;
-
- import android.app.Activity;
- import android.app.FragmentManager;
- import android.app.FragmentTransaction;
- import android.os.Bundle;
-
- public class MainActivity extends Activity {
-
- private final String TAG = "--MainActivity---> ";
-
- private FragmentManager manager;
- private FragmentTransaction transaction;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- System.out.println(TAG + " onCreate");
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- manager = getFragmentManager();
- transaction = manager.beginTransaction();
- transaction.add(R.id.lt_frame, new MyFragment());
- transaction.commit();
- }
-
- @Override
- protected void onStart() {
-
- System.out.println(TAG + " onStart");
- super.onStart();
- }
-
- @Override
- protected void onResume() {
-
- System.out.println(TAG + " onResume");
- super.onResume();
- }
-
- @Override
- protected void onPause() {
-
- System.out.println(TAG + " onPause");
- super.onPause();
- }
-
- @Override
- protected void onStop() {
-
- System.out.println(TAG + " onStop");
- super.onStop();
- }
-
- @Override
- protected void onDestroy() {
-
- System.out.println(TAG + " onDestroy");
- super.onDestroy();
- }
-
- }
类似的,同样声明了Activity生命周期中的所有方法以及打印语句,并且当Activity创建时将MyFragment动态添加到activity_main.xml中的FrameLayout布局文件里,可以看到这个布局文件是空的,所以它就相当于用来装fragment的容器了。
下面看一下运行效果和LogCat控制台的打印结果:
![Fragment进阶篇之Fragment生命周期和回退栈_第8张图片](http://img.e-com-net.com/image/info8/97ece9f5439444b487306dc04bf92a8d.gif)
可以看到fragment正常被加载到了Activity的FrameLayout中了,那么现在看看LogCat:
![Fragment进阶篇之Fragment生命周期和回退栈_第9张图片](http://img.e-com-net.com/image/info8/3f602de4b0494e3792677941145d1297.jpg)
可以看到首先是Activity被创建,紧接着fragment与Activity绑定(onAttach),然后fragment被创建(onCreat),fragment的视图被创建(onCreatView),fragment所在的Activity的onCreate()方法已经被返回(onActivityCreated),最后Actvity启动,fragment启动,Activity处于运行状态,fragment处于运行状态。
当我点返回键之后,再看一下运行效果和LogCat控制台的打印结果:
![Fragment进阶篇之Fragment生命周期和回退栈_第10张图片](http://img.e-com-net.com/image/info8/43f3109847a54edf9a8bad1893c9c70d.gif)
可以看到已经点击返回键退出应用了,那么现在看看LogCat:
![Fragment进阶篇之Fragment生命周期和回退栈_第11张图片](http://img.e-com-net.com/image/info8/96ea2f4844044dcd8ba4bda1bc33b92e.jpg)
可以看到退出的时候,首先是fragment暂停、Activity暂停,然后fragment停止、Activity停止,然后销毁fragment的视图(onDestoryView,与onCreatView相对应)、与之前绑定的Activity解除关联(onDetach,与onAttach相对应),最后是Activity的销毁。
通过上面的分析我们可以证实:
fragment的生命周期确实是伴随着Activity的生命周期变化的,并且它是依附于Activity的。先创建Activity,再创建fragment,先销毁fragment,再销毁Activity,这种层次结构的设计也是非常合理的,而且和“栈”的结构有些相似,即:“后进先出”。下面将记录fragment的另一个重要的概念,即“回退栈(back stack)”。
三、回退栈(back stack)
其实回退栈很简单,fragment的回退栈和Activity的回退栈是类似的,就是如果把一个fragment事务添加到回退栈,那么点返回按钮的时候也就可以看到上一次保存的fragment,不至于直接退出Activity。也就是通过这个方法来将fragment事务添加到回退栈的:
- transaction.addToBackStack(String name);
下面通过例子来看看回退栈的应用,顺便再说说我在学习回退栈的同时学到的其它相关知识,对于我来说还是很有意义的。需求是这样的:同样是上面的英雄列表,当我点击ListView的某一项时,下面的fragment就替换成一个新的界面,这个界面有一个文本框,需要输入当前项的英雄名称,还有一个确定按钮,点击确定时,如果输入的和当前项的英雄名一致,就弹出土司提示正确并附加英雄名,如果输入的和当前项的英雄名不一致,也弹出土司提示错误,但不显示英雄名。重点是,我在二级界面点击返回的时候,要跳回ListView的界面,下面贴上我重构后的代码。
Layout代码(f1.xml-->二级界面的布局文件):
- xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical" >
-
- <TextView
- android:id="@+id/tv_textView_f1"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="0.7"
- android:background="#F7F7F7"
- android:gravity="center"
- android:text="我是HERO,我的名字是?"
- android:textSize="20sp" />
-
- <EditText
- android:id="@+id/et_editText_e1"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="0.15"
- android:inputType="textPersonName"
- android:hint="请输入英雄名" />
-
- <Button
- android:id="@+id/btn_button_b1"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="0.15"
- android:text="确定" />
-
- LinearLayout>
MyFragment代码(只重构了onCreatView方法):
- package com.example.fragmentlifecycledemo;
-
- import android.app.Fragment;
- import android.os.Bundle;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.view.ViewGroup;
- import android.widget.Button;
- import android.widget.EditText;
- import android.widget.Toast;
-
- public class MySubFragment extends Fragment implements OnClickListener {
- private Button mButton;
- private EditText editText1;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
-
- super.onCreate(savedInstanceState);
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
-
- View v = inflater.inflate(R.layout.f1, container, false);
- editText1 = (EditText) v.findViewById(R.id.et_editText_e1);
- mButton = (Button) v.findViewById(R.id.btn_button_b1);
- mButton.setOnClickListener(this);
- return v;
- }
-
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
-
- super.onActivityCreated(savedInstanceState);
- }
-
- @Override
- public void onPause() {
-
- super.onPause();
- }
-
- @Override
- public void onClick(View v) {
-
- String name = (String) getArguments().getCharSequence("heroName");
-
- String input = editText1.getText().toString();
- if (name.equals(input)) {
- Toast.makeText(getActivity(), "回答正确!我的名字是:" + name,
- Toast.LENGTH_LONG).show();
- } else {
- Toast.makeText(getActivity(), "回答错误!我不告诉你我的名字!", Toast.LENGTH_LONG)
- .show();
- }
- }
- }
下面再看一下重构后的运行效果:
可以看到点击Item跳转之后,再点击返回按钮又可以成功返回到ListView,而不会直接退出程序,这就是fragment回退栈的作用了,其实在重构这些代码时我思考更多的是如何将ListView中Item的值传到二级fragment中,之前的做法是:直接在MyFragment的onItemClick方法中得到Item的View和二级Fragment的View,通过xxx.getText(“”+xxx.setText)这种方式去做,结果一直报错,后来整理了思路,结合上面学习的生命周期,我理解了fragment的View都是在各自的onCreatView方法中完成的,这样把代码分开才最终解决了问题。
四、结合回退栈再看生命周期
加了回退栈之后,我们有必要看看点击返回按钮之后生命周期的变化,下面就贴上从桌面进入APP、点击一项Item、点击返回、再点击返回退出APP的完整的生命周期输出信息。
![Fragment进阶篇之Fragment生命周期和回退栈_第12张图片](http://img.e-com-net.com/image/info8/3d4f777927aa4994994b0bca11ae4427.jpg)
注意红色方框一级Fragment跳到二级Fragment的时候只调用的onDestoryView(),并没有调用onDestory,而点击返回的时候,自然就直接调用onCreatView,这也正是回退栈的作用了。
五、总结
其实我想重构这个例子只是测试一下回退栈,但设计需求的同时又想把ListView中每个Item项的文本信息传到跳转之后的二级fragment中,所以我先理清思路,发现问题所在,并仔细思考了如何传递数据、在哪里保存数据又应该在哪里读取数据,最后完成需求。这样在无形之中又学到了更多,我也明白了学一个知识的时候不能仅仅满足于表面,往往在你发掘需求的同时就又会发现一些更有意思的事情,本篇先记录到这里,以后还要继续加油!更加努力!
原文:http://blog.csdn.net/wlwlwlwl015/article/details/40584567