首页 > 代码库 > 关于FragmentManager动态管理Fragment时Fragment生命周期的探究
关于FragmentManager动态管理Fragment时Fragment生命周期的探究
Fragment是Android中的重要组件,在Android 3.0的时候添加进来。
关于Fragment的生命周期,我相信了解过的开发人员都应该把以下方法脱口而出:onAttach, onCreate, onCreateView, onViewCreated, onActivityCreated, onStart, onResume, onPause, onStop, onDestroyView, onDestroy, onDetach.
当Fragment以静态的方式,即通过在布局文件中以其它控件的方式设置时,它的生命周期随所在Activity的生命周期而发生变化。此时其生命周期的方法调用过程是这样的:
1,当首次展示布局页面时,其生命周期方法调用的顺序是:
2,而当关闭手机屏幕或者手机屏幕变暗时,其其生命周期方法调用的顺序是:
3,当再次对手机屏幕解锁或者手机屏幕变亮时,其生命周期方法调用的顺序是:
4,而当对当前Fragment所在屏幕按返回键时,其生命周期方法调用的顺序是:
1 01-13 17:08:46.959 3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onPause2 01-13 17:08:46.959 3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onStop3 01-13 17:08:46.959 3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onDestroyView4 01-13 17:08:46.959 3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onDestroy5 01-13 17:08:46.959 3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onDetach
但是当使用FragmentManager动态的管理Fragment并且涉及到是否addToBackStack时,其生命周期的展现就略微显得有些复杂了。但是还没有复杂到无法理解。
好,下面,我们就探究一下这些问题。
首先,我们重写了两个Fragment,主要是重写了它们的生命周期方法,通过在其生命周期方法中打印出Log的方式来显示其方法的调用。
两个类分别是:
1 package com.yeepay.fraglifecircletest.frag; 2 3 import android.app.Activity; 4 import android.app.Fragment; 5 import android.os.Bundle; 6 import android.util.Log; 7 import android.view.LayoutInflater; 8 import android.view.View; 9 import android.view.ViewGroup;10 11 import com.yeepay.fraglifecircletest.R;12 13 public class FragA extends Fragment {14 private static final String TAG = FragA.class.getSimpleName();15 16 @Override17 public void onAttach(Activity activity) {18 super.onAttach(activity);19 Log.i(TAG, "onAttach");20 }21 22 @Override23 public void onCreate(Bundle savedInstanceState) {24 super.onCreate(savedInstanceState);25 Log.i(TAG, "onCreate");26 }27 28 @Override29 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {30 Log.i(TAG, "onCreateView");31 return inflater.inflate(R.layout.fragment_test_a, null, false);32 }33 34 @Override35 public void onViewCreated(View view, Bundle savedInstanceState) {36 Log.i(TAG, "onViewCreated");37 super.onViewCreated(view, savedInstanceState);38 }39 40 @Override41 public void onDestroy() {42 Log.i(TAG, "onDestroy");43 super.onDestroy();44 }45 46 @Override47 public void onDetach() {48 Log.i(TAG, "onDetach");49 super.onDetach();50 }51 52 @Override53 public void onDestroyView() {54 Log.i(TAG, "onDestroyView");55 super.onDestroyView();56 }57 58 @Override59 public void onStart() {60 Log.i(TAG, "onStart");61 super.onStart();62 }63 64 @Override65 public void onStop() {66 Log.i(TAG, "onStop");67 super.onStop();68 }69 70 @Override71 public void onResume() {72 Log.i(TAG, "onResume");73 super.onResume();74 }75 76 @Override77 public void onPause() {78 Log.i(TAG, "onPause");79 super.onPause();80 }81 82 @Override83 public void onActivityCreated(Bundle savedInstanceState) {84 Log.i(TAG, "onActivityCreated");85 super.onActivityCreated(savedInstanceState);86 }87 }
1 package com.yeepay.fraglifecircletest.frag; 2 3 import android.app.Activity; 4 import android.app.Fragment; 5 import android.os.Bundle; 6 import android.util.Log; 7 import android.view.LayoutInflater; 8 import android.view.View; 9 import android.view.ViewGroup;10 11 import com.yeepay.fraglifecircletest.R;12 13 public class FragB extends Fragment {14 private static final String TAG = FragB.class.getSimpleName();15 16 @Override17 public void onAttach(Activity activity) {18 super.onAttach(activity);19 Log.i(TAG, "onAttach");20 }21 22 @Override23 public void onCreate(Bundle savedInstanceState) {24 super.onCreate(savedInstanceState);25 Log.i(TAG, "onCreate");26 }27 28 @Override29 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {30 Log.i(TAG, "onCreateView");31 return inflater.inflate(R.layout.fragment_test_b, null, false);32 }33 34 @Override35 public void onViewCreated(View view, Bundle savedInstanceState) {36 Log.i(TAG, "onViewCreated");37 super.onViewCreated(view, savedInstanceState);38 }39 40 @Override41 public void onDestroy() {42 Log.i(TAG, "onDestroy");43 super.onDestroy();44 }45 46 @Override47 public void onDetach() {48 Log.i(TAG, "onDetach");49 super.onDetach();50 }51 52 @Override53 public void onDestroyView() {54 Log.i(TAG, "onDestroyView");55 super.onDestroyView();56 }57 58 @Override59 public void onStart() {60 Log.i(TAG, "onStart");61 super.onStart();62 }63 64 @Override65 public void onStop() {66 Log.i(TAG, "onStop");67 super.onStop();68 }69 70 @Override71 public void onResume() {72 Log.i(TAG, "onResume");73 super.onResume();74 }75 76 @Override77 public void onPause() {78 Log.i(TAG, "onPause");79 super.onPause();80 }81 82 @Override83 public void onActivityCreated(Bundle savedInstanceState) {84 Log.i(TAG, "onActivityCreated");85 super.onActivityCreated(savedInstanceState);86 }87 }
1,当我们通过以下方式添加FragA时,
1 FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();2 fragA = new FragA();3 fragmentTransaction.replace(R.id.frag_container, fragA, fragNames[0]);4 fragmentTransaction.commit();
它的生命周期展示方式是同在布局文件中静态设置的表现一模一样的,这里不再详细展开,大家可以查看一下以上内容。
2,当我们以如下方式展示FragA并且没有addToBackStack时,
1 @Override 2 public void onClick(View v) { 3 FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); 4 switch (v.getId()) { 5 case R.id.button1: 6 if (fragA == null) { 7 fragA = new FragA(); 8 fragmentTransaction.replace(R.id.frag_container, fragA, fragNames[0]); 9 // fragmentTransaction.addToBackStack(fragNames[0]);10 } else {11 Fragment fragment = fragmentManager.findFragmentByTag(fragNames[0]);12 fragmentTransaction.replace(R.id.frag_container, fragment, fragNames[0]);13 }14 break;15 case R.id.button2:16 if (fragB == null) {17 fragB = new FragB();18 fragmentTransaction.replace(R.id.frag_container, fragB, fragNames[1]);19 // fragmentTransaction.addToBackStack(fragNames[1]);20 } else {21 Fragment fragment = fragmentManager.findFragmentByTag(fragNames[1]);22 fragmentTransaction.replace(R.id.frag_container, fragment, fragNames[1]);23 }24 break;25 default:26 break;27 }28 fragmentTransaction.commit();29 }
FragA生命周期调用顺序是:
此时,如果再点击另外一个按钮B,将FragB展示出来,FragA和FragB的生命周期展示方式是:
可以看到,FragA调用顺序为onPause, onStop, onDestroyView, onDestroy, onDetach.这说明,FragA已经被FragmentManager完全抛弃了,取而代之的是FragB的完全展现。而如果此时按返回键的话,FragB的生命周期也将是onPause, onStop, onDestroyView, onDestroy, onDetach。这说明,在添加Fragment时如果没有调用addToBackStack方式的话,当FragmentManager更换Fragment时,是不保存Fragment的状态的。
3,下面我们在替换Fragment时顺便addToBackStack,则其生命周期展现方式是:
1 replace FragA and addToBackStack2 ########################################################################################3 01-13 17:08:43.359 3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onAttach4 01-13 17:08:43.359 3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onCreate5 01-13 17:08:43.359 3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onCreateView6 01-13 17:08:43.359 3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onViewCreated7 01-13 17:08:43.359 3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onActivityCreated8 01-13 17:08:43.359 3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onStart9 01-13 17:08:43.359 3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onResume
可以看得出来,此时的生命周期方法调用是跟没有addToBackStack时没有任何区别的。
然后通过点击按钮B,使用FragB来替换FragA,此时FragA和FragB的生命周期方法调用顺序是:
1 and then replace FragB and addToBackStack 2 &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 3 01-13 17:08:46.959 3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onPause 4 01-13 17:08:46.959 3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onStop 5 01-13 17:08:46.959 3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onDestroyView 6 01-13 17:08:46.959 3102-3102/com.yeepay.fraglifecircletest I/FragB﹕ onAttach 7 01-13 17:08:46.959 3102-3102/com.yeepay.fraglifecircletest I/FragB﹕ onCreate 8 01-13 17:08:46.959 3102-3102/com.yeepay.fraglifecircletest I/FragB﹕ onCreateView 9 01-13 17:08:46.959 3102-3102/com.yeepay.fraglifecircletest I/FragB﹕ onViewCreated10 01-13 17:08:46.959 3102-3102/com.yeepay.fraglifecircletest I/FragB﹕ onActivityCreated11 01-13 17:08:46.959 3102-3102/com.yeepay.fraglifecircletest I/FragB﹕ onStart12 01-13 17:08:46.959 3102-3102/com.yeepay.fraglifecircletest I/FragB﹕ onResume
由此可以看出,FragA生命周期方法只是调用到了onDestroyView,而onDestroy和onDetach则没有被调用,这说明FragA的界面已经被销毁了,但是FragmentManager并没有完全销毁FragA,FragA依然有状态保存在FragmentManager里面。
然后再点击按钮A,使用FragA来替换当前显示的FragB,此时FragA和FragB的生命周期方法调用顺序为:
1 and then replace FragA again 2 &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 3 01-13 17:08:51.869 3102-3102/com.yeepay.fraglifecircletest I/FragB﹕ onPause 4 01-13 17:08:51.869 3102-3102/com.yeepay.fraglifecircletest I/FragB﹕ onStop 5 01-13 17:08:51.869 3102-3102/com.yeepay.fraglifecircletest I/FragB﹕ onDestroyView 6 01-13 17:08:51.869 3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onCreateView 7 01-13 17:08:51.869 3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onViewCreated 8 01-13 17:08:51.869 3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onActivityCreated 9 01-13 17:08:51.869 3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onStart10 01-13 17:08:51.869 3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onResume
可以看到,FragB的生命方法调用顺序是跟FragB替换FragA时FragA的调用顺序一致的,作用就是只销毁了视图,但是依然保留了Fragment的状态。而此时FragA的调用则值得注意,此时FragA直接从onCreateView调起,也就是说只是重新创建了视图,而依然使用上次被替换时的Fragment状态。
OK,说到此时,是否对Fragment的生命周期方法调用在是否addToBackStack时不同有所更加深入的了解了呢?
好吧,最后一个问题。是关于Fragment在FragmentManager管理时,show和hide时的生命周期方法调用。
此时的调用实现方式为:
1 FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); 2 switch (v.getId()) { 3 case R.id.button1: 4 hideAllFrags(fragmentTransaction); 5 if (fragA == null) { 6 fragA = new FragA(); 7 fragmentTransaction.add(R.id.frag_container, fragA, fragNames[0]); 8 fragmentTransaction.addToBackStack(fragNames[0]); 9 } else {10 fragmentTransaction.show(fragA);11 }12 break;13 case R.id.button2:14 hideAllFrags(fragmentTransaction);15 if (fragB == null) {16 fragB = new FragB();17 fragmentTransaction.add(R.id.frag_container, fragB, fragNames[1]);18 fragmentTransaction.addToBackStack(fragNames[1]);19 } else {20 fragmentTransaction.show(fragB);21 }22 break;23 default:24 break;25 }26 fragmentTransaction.commit();
细心的话可以发现,在展示Fragment时,我们使用了方法add而非上面用的replace。而且直接addToBackStack。其实这也可以理解,你想,FragmentManager在show或者hide时,肯定是已经存在的,或者如果没有的话,需要添加进来Fragment。这便是在show和hide时,需要注意的地方,即使用add和addToBackStack方法。
在点击按钮A时,FragA的调用顺序为:
1 01-15 16:57:20.390 9225-9225/com.yeepay.fraglifecircletest I/hideAllFrags﹕ hideAllFrags2 01-15 16:57:20.390 9225-9225/com.yeepay.fraglifecircletest I/FragA﹕ onAttach3 01-15 16:57:20.390 9225-9225/com.yeepay.fraglifecircletest I/FragA﹕ onCreate4 01-15 16:57:20.390 9225-9225/com.yeepay.fraglifecircletest I/FragA﹕ onCreateView5 01-15 16:57:20.390 9225-9225/com.yeepay.fraglifecircletest I/FragA﹕ onViewCreated6 01-15 16:57:20.390 9225-9225/com.yeepay.fraglifecircletest I/FragA﹕ onActivityCreated7 01-15 16:57:20.390 9225-9225/com.yeepay.fraglifecircletest I/FragA﹕ onStart8 01-15 16:57:20.390 9225-9225/com.yeepay.fraglifecircletest I/FragA﹕ onResume
可以看出没有什么不同于以上所言的部分。
然后,点击按钮B时,FragA和FragB的调用顺序为:
1 01-15 16:57:23.360 9225-9225/com.yeepay.fraglifecircletest I/hideAllFrags﹕ hideAllFrags2 01-15 16:57:23.360 9225-9225/com.yeepay.fraglifecircletest I/FragB﹕ onAttach3 01-15 16:57:23.360 9225-9225/com.yeepay.fraglifecircletest I/FragB﹕ onCreate4 01-15 16:57:23.360 9225-9225/com.yeepay.fraglifecircletest I/FragB﹕ onCreateView5 01-15 16:57:23.370 9225-9225/com.yeepay.fraglifecircletest I/FragB﹕ onViewCreated6 01-15 16:57:23.370 9225-9225/com.yeepay.fraglifecircletest I/FragB﹕ onActivityCreated7 01-15 16:57:23.370 9225-9225/com.yeepay.fraglifecircletest I/FragB﹕ onStart8 01-15 16:57:23.370 9225-9225/com.yeepay.fraglifecircletest I/FragB﹕ onResume
可以看出,FragA并没有调用生命周期方法,这说明是展示FragB时,FragA的生命周期并没有发生变化。而FragB的生命周期与初次点击按钮A时FragA的生命周期方法相同。
然后再继续点击按钮A和B,此时打印出来的log为:
1 01-15 16:57:25.220 9225-9225/com.yeepay.fraglifecircletest I/hideAllFrags﹕ hideAllFrags2 01-15 16:57:44.990 9225-9225/com.yeepay.fraglifecircletest I/hideAllFrags﹕ hideAllFrags3 01-15 16:57:47.350 9225-9225/com.yeepay.fraglifecircletest I/hideAllFrags﹕ hideAllFrags4 01-15 16:57:48.020 9225-9225/com.yeepay.fraglifecircletest I/hideAllFrags﹕ hideAllFrags
这说明在FragA和FragB添加进BackStack之后无论如何地show或者hide,它们的生命周期不再发生变化。
而当屏幕上锁或变暗,然后再解锁或者变亮时,FragA和FragB的生命周期方法调用顺序为:
1 when screen is locked: 2 ########################################################################################### 3 01-15 16:58:36.840 9225-9225/com.yeepay.fraglifecircletest I/FragA﹕ onPause 4 01-15 16:58:36.840 9225-9225/com.yeepay.fraglifecircletest I/FragB﹕ onPause 5 01-15 16:58:36.870 9225-9225/com.yeepay.fraglifecircletest I/FragA﹕ onStop 6 01-15 16:58:36.880 9225-9225/com.yeepay.fraglifecircletest I/FragB﹕ onStop 7 8 when screen is unlocked: 9 ##########################################################################################10 01-15 17:05:01.850 9225-9225/com.yeepay.fraglifecircletest I/FragA﹕ onStart11 01-15 17:05:01.850 9225-9225/com.yeepay.fraglifecircletest I/FragB﹕ onStart12 01-15 17:05:01.870 9225-9225/com.yeepay.fraglifecircletest I/FragA﹕ onResume13 01-15 17:05:01.870 9225-9225/com.yeepay.fraglifecircletest I/FragB﹕ onResume
可以看得出来,两个Fragment都调用了onPause, onStop, onStart, onResume。而且FragA的调用要在FragB之前,这说明跟他们添加进BackStack的顺序有关。
以上就是我对Fragment在被FragmentManager管理时,其生命周期方法调用顺序的探究,大家觉得如果有什么地方不严谨或者不准确的地方,欢迎在留言处告知。
示例工程下载地址为:FragLifeCircleTest
关于FragmentManager动态管理Fragment时Fragment生命周期的探究