在基于上一篇关于Activity的生命周期的深入了解之后,我想大家应该开始意识到一个问题就是,虽然有些类,接口,方法平时经常使用,但是只是了解一个大概,当在面试的时候考官一深入去体察你的知识深度,你就hold不住了。那么在这篇文章中,我们开始针对Fragment的生命周期进行一些知识挖掘,我依然会带大家通过阅读源码的方式了解Fragment。
Fragment的生命周期
在这一节中,我相信大家作为开发者都应该对Fragment的生命周期有一个简单的了解了,并且能够随口说出生命周期的方法执行顺序,那么在这一节我也就不过多赘述。通过代码执行的结果来验证:
(1)Fragment首次展示时:
07-17 08:41:51.441 9232-9232/com.kanzhun.lifecycle D/FragmentA: onAttach
07-17 08:41:51.441 9232-9232/com.kanzhun.lifecycle D/FragmentA: onCreate
07-17 08:41:51.451 9232-9232/com.kanzhun.lifecycle D/FragmentA: onCreateView
07-17 08:41:51.461 9232-9232/com.kanzhun.lifecycle D/FragmentA: onViewCreated
07-17 08:41:51.461 9232-9232/com.kanzhun.lifecycle D/FragmentA: onActivityCreated
07-17 08:41:51.461 9232-9232/com.kanzhun.lifecycle D/FragmentA: onStart
07-17 08:41:51.461 9232-9232/com.kanzhun.lifecycle D/FragmentA: onResume
(2)Fragment进入后台或者锁屏时:
07-17 08:44:28.871 9232-9232/com.kanzhun.lifecycle D/FragmentA: onPause
07-17 08:44:29.241 9232-9232/com.kanzhun.lifecycle D/FragmentA: onStop
(3)Fragment从后台返回前台或者点亮屏幕时:
07-17 08:45:42.711 9232-9232/com.kanzhun.lifecycle D/FragmentA: onStart
07-17 08:45:42.711 9232-9232/com.kanzhun.lifecycle D/FragmentA: onResume
(4)销毁Fragment的时候:
07-17 08:46:40.291 9232-9232/com.kanzhun.lifecycle D/FragmentA: onPause
07-17 08:46:40.631 9232-9232/com.kanzhun.lifecycle D/FragmentA: onStop
07-17 08:46:40.631 9232-9232/com.kanzhun.lifecycle D/FragmentA: onDestroyView
07-17 08:46:40.631 9232-9232/com.kanzhun.lifecycle D/FragmentA: onDestroy
07-17 08:46:40.631 9232-9232/com.kanzhun.lifecycle D/FragmentA: onDetach
由此来看,我们通过日志的打印又重新对于Fragment的生命周期进行了一次简单的回顾。
addToBackStack()方法对于生命周期的影响
我在这里准备了一段代码:
public class FragmentLifecycleActivity extends FragmentActivity implements View.OnClickListener {
private FragmentManager fm;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragment_lifecycle);
findViewById(R.id.btn_fragmentA).setOnClickListener(this);
findViewById(R.id.btn_fragmentB).setOnClickListener(this);
fm = getSupportFragmentManager();
}
@Override
public void onClick(View view) {
FragmentTransaction ft = fm.beginTransaction();
switch (view.getId()) {
case R.id.btn_fragmentA:
ft.replace(R.id.ll_container, FragmentA.getInstance(null));
ft.addToBackStack(null);
ft.commit();
break;
case R.id.btn_fragmentB:
ft.replace(R.id.ll_container, FragmentB.getInstance(null));
ft.addToBackStack(null);
ft.commit();
break;
default:
break;
}
}
}
在以上的代码中,我采取replace()的方式替换之前所存在的fragment,并且每次替换Fragment时都添加addToBackStack()方法,我们看看他对于生命周期有什么影响:
(1)首次启动FragmentA时,由于FragmentManager中没有存在FragmentA,所以FragmentA依然运行自己生命周期的方法:
07-17 09:03:38.441 26271-26271/com.kanzhun.lifecycle D/FragmentA: onAttach
07-17 09:03:38.441 26271-26271/com.kanzhun.lifecycle D/FragmentA: onCreate
07-17 09:03:38.441 26271-26271/com.kanzhun.lifecycle D/FragmentA: onCreateView
07-17 09:03:38.441 26271-26271/com.kanzhun.lifecycle D/FragmentA: onViewCreated
07-17 09:03:38.441 26271-26271/com.kanzhun.lifecycle D/FragmentA: onActivityCreated
07-17 09:03:38.441 26271-26271/com.kanzhun.lifecycle D/FragmentA: onStart
07-17 09:03:38.441 26271-26271/com.kanzhun.lifecycle D/FragmentA: onResume
(2)这时,点击fragmentB的按钮让FragmentB去替换FragmentA:
07-17 09:08:24.531 26271-26271/com.kanzhun.lifecycle D/FragmentB: onAttach
07-17 09:08:24.531 26271-26271/com.kanzhun.lifecycle D/FragmentB: onCreate
07-17 09:08:24.531 26271-26271/com.kanzhun.lifecycle D/FragmentA: onPause
07-17 09:08:24.531 26271-26271/com.kanzhun.lifecycle D/FragmentA: onStop
07-17 09:08:24.531 26271-26271/com.kanzhun.lifecycle D/FragmentA: onDestroyView
07-17 09:08:24.531 26271-26271/com.kanzhun.lifecycle D/FragmentB: onCreateView
07-17 09:08:24.531 26271-26271/com.kanzhun.lifecycle D/FragmentB: onViewCreated
07-17 09:08:24.531 26271-26271/com.kanzhun.lifecycle D/FragmentB: onActivityCreated
07-17 09:08:24.531 26271-26271/com.kanzhun.lifecycle D/FragmentB: onStart
07-17 09:08:24.531 26271-26271/com.kanzhun.lifecycle D/FragmentB: onResume
在FragmentB启动之后,我们发现FragmentA虽然被替换并且运行了onDestroyView()方法,但是并没有运行onDestroy()和onDetach()方法。
(3)当我们这时按下返回键时:
07-17 09:14:12.221 26271-26271/com.kanzhun.lifecycle D/FragmentB: onPause
07-17 09:14:12.221 26271-26271/com.kanzhun.lifecycle D/FragmentB: onStop
07-17 09:14:12.221 26271-26271/com.kanzhun.lifecycle D/FragmentB: onDestroyView
07-17 09:14:12.221 26271-26271/com.kanzhun.lifecycle D/FragmentB: onDestroy
07-17 09:14:12.221 26271-26271/com.kanzhun.lifecycle D/FragmentB: onDetach
07-17 09:14:12.231 26271-26271/com.kanzhun.lifecycle D/FragmentA: onCreateView
07-17 09:14:12.231 26271-26271/com.kanzhun.lifecycle D/FragmentA: onViewCreated
07-17 09:14:12.231 26271-26271/com.kanzhun.lifecycle D/FragmentA: onActivityCreated
07-17 09:14:12.231 26271-26271/com.kanzhun.lifecycle D/FragmentA: onStart
07-17 09:14:12.231 26271-26271/com.kanzhun.lifecycle D/FragmentA: onResume
FragmentA被重新展现出来,我们发现此时FragmentB由于调用了onDestroy()和onDetach()方法已经完全被抛弃。FragmentA由于在FragmentManager的栈中依然存在,所以不需要调用onAttach()和onCreate()方法。
而对比没有添加addToBackStack()方法的结果,我们发现:
(1)栈中只会存在一个Fragment。
(2)FragmentB替换FragmentA的时候,FragmentA中的onDestroy()和onDetach()方法一定会被调用。
在源码中,我们找到了addToBackStack()的意义:
在每一次transaction执行commit()方法后,该次这对某fragment的transaction事件状态将会被记住。一旦这个fragment再次回到栈顶时,继续根据之前保留的transaction状态对fragment执行操作。
/**
* Add this transaction to the back stack. This means that the transaction
* will be remembered after it is committed, and will reverse its operation
* when later popped off the stack.
*
* @param name An optional name for this back stack state, or null.
*/
public abstract FragmentTransaction addToBackStack(@Nullable String name);
hide()和show()对于生命周期的影响
接下来,我们改造一下代码,先把FragmentA和FragmentB通过add()的方式加入到FragmentManager中,之后再以show()和hide()的调用方式控制其显示还是隐藏。看看用这种方式对于Fragment的生命周期有什么影响。
首先,将Fragment的添加方式进行改造:
@Override
public void onClick(View view) {
FragmentTransaction ft = fm.beginTransaction();
switch (view.getId()) {
case R.id.btn_fragmentA:
hideAllFragments(ft);
if (fragmentA == null) {
fragmentA = FragmentA.getInstance(null);
ft.add(R.id.ll_container, fragmentA);
ft.addToBackStack(null);
} else {
ft.show(fragmentA);
}
ft.commit();
break;
case R.id.btn_fragmentB:
hideAllFragments(ft);
if (fragmentB == null) {
fragmentB = FragmentB.getInstance(null);
ft.add(R.id.ll_container, fragmentB);
ft.addToBackStack(null);
} else {
ft.show(fragmentB);
}
ft.commit();
break;
default:
break;
}
}
如果Fragment已经被加入到FragmentManager了,我们需要在该fragment显示之前,先隐藏所有的Fragment。
private void hideAllFragments(FragmentTransaction ft) {
List<Fragment> fragments = fm.getFragments();
if (fragments == null || fragments.size() <= 0) return;
for (Fragment f : fragments) {
if (f == null) continue;
ft.hide(f);
}
}
运行代码之后,我们可以看到如下结果:
(1)点击FragmentA将FragmentA添加到FragmentManager时,FragmentA会调用自己的生命周期如下方法。
07-17 18:47:58.179 16467-16467/com.kanzhun.lifecycle D/FragmentA: onAttach
07-17 18:47:58.189 16467-16467/com.kanzhun.lifecycle D/FragmentA: onCreate
07-17 18:47:58.189 16467-16467/com.kanzhun.lifecycle D/FragmentA: onCreateView
07-17 18:47:58.189 16467-16467/com.kanzhun.lifecycle D/FragmentA: onViewCreated
07-17 18:47:58.189 16467-16467/com.kanzhun.lifecycle D/FragmentA: onActivityCreated
07-17 18:47:58.189 16467-16467/com.kanzhun.lifecycle D/FragmentA: onStart
07-17 18:47:58.189 16467-16467/com.kanzhun.lifecycle D/FragmentA: onResume
(2)点击FragmentB再将FragmentB添加到FragmentManager时,FragmentB也会调用自己的生命周期如下方法。
07-17 18:49:37.169 16467-16467/com.kanzhun.lifecycle D/FragmentB: onAttach
07-17 18:49:37.169 16467-16467/com.kanzhun.lifecycle D/FragmentB: onCreate
07-17 18:49:37.169 16467-16467/com.kanzhun.lifecycle D/FragmentB: onCreateView
07-17 18:49:37.169 16467-16467/com.kanzhun.lifecycle D/FragmentB: onViewCreated
07-17 18:49:37.169 16467-16467/com.kanzhun.lifecycle D/FragmentB: onActivityCreated
07-17 18:49:37.169 16467-16467/com.kanzhun.lifecycle D/FragmentB: onStart
07-17 18:49:37.169 16467-16467/com.kanzhun.lifecycle D/FragmentB: onResume
(3)再次点击A、B之后,则不再有生命周期方法的调用。
(4)点击返回键:
1> 如果在add()调用前添加了addToBackStack()方法,那么会将两个fragment依次pop出栈。最后添加进FragmentManager的Fragment最先出栈。
2> 如果在add()时没有调用addToBackStack()方法,那么点击一次返回键,会将两个fragment全部移除出栈。
这两种方式的移除都会调用onDestroy()和onDetach()方法。
通过代码我们可以得出结论:
一旦Fragment被添加之后,hide()和show()方法的调用不会引起Fragment生命周期方法的调用。
小结:
通过以上的代码分析,我们可以看出了解Fragment的生命周期有助于我们去选择合适的方式去构建我们的工程。由于现在Fragment使用起来更加灵活,我们也可以通过Fragment去打造更简单的并且更好维护的工程体系,来帮助我们完成复杂的业务逻辑。