对Fragment生命周期的一点领悟

xiaoxiao2021-02-28  95

前言

最近在看Fragment方面的东西,项目中的页面基本使用Fragment实现,整个项目只有2个Activity,闪屏和主Activity,其他均使用Fragment写成。还不知道Fragment是什么的同学可以看一下这篇,谷歌的官方文档,其他部分也非常好,我看了一遍感觉从中学到了很多,推荐大家也能抽时间看一下,很有好处。


Fragment的生命周期

下图是整个Fragment的生命周期示意图:

整个Fragment和Activity非常相似,但多了onAttach、onDetach、onCreateView、onDestroyView及onActivityCreate等方法。 下面大致讲一下这几个方法的回调时机:

onAttach方法:called once the fragment is associated with its activity. (当Fragment与Activity关联时调用)onDetach方法:called immediately prior to the fragment no longer being associated with its activity.(当Fragment与Activity不再关联时调用)onCreateView方法:creates and returns the view hierarchy associated with the fragment.(onCreate方法调用后被调用,用来返回该Fragment的布局)onDestroyView方法:allows the fragment to clean up resources associated with its View.(onStop方法调用后被调用,用来取消布局与Fragment的关联)onActivityCreated方法:tells the fragment that its activity has completed its own Activity.onCreate().(在Fragment所在的Activity执行完onCreate方法后调用)

除了以上说到的常见的生命周期,Fragment也有像Activity中onSaveInstanceState、onRestoreInstanceState用来存储当前视图状态的方法,对应onSaveInstanceState和onViewStateRestored方法。另外,onHiddenChanged方法也很常用,当Fragment显示或隐藏时调用,当然,Fragment生命周期还有很多可以研究的,可以根据业务做不同的处理。

管理Fragment

管理部分不多说,依然可以查看官方文档–>管理部分。

重点来了

看了上面的管理部分后,来到了我们今天的重点内容:当我们有切换Fragment的需求时,通常有以下两种方式:


使用add方法添加新的Fragment,将旧的Fragment使用hide方法隐藏使用replace方法,切换Fragment

下面以Fragment1作为当前Fragment,以Fragment2作为要添加的Fragment作为例子:

使用add方法的情况:

载入Fragment1:

Fragment1 onCreate Fragment1 onCreateView Fragment1 onStart Fragment1 onResume

用以下代码切到Fragment2: FragmentTransaction ft = getFragmentManager().beginTransaction(); ft.hide(Fragment1); ft.add(R.id.simple_fragment, Fragment2); ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN); ft.commit();

此时Fragment1不会走任何生命周期,但会回调onHiddenChanged方法 Fragment生命周期:

Fragment2 onCreate Fragment2 onCreateView Fragment2 onStart Fragment2 onResume

回到Fragment1,remove Fragment2: FragmentTransaction ft = getFragmentManager().beginTransaction(); ft.remove(Fragment2); ft.show(Fragment1); ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN); ft.commit();

此时Fragment依然不走任何生命周期,回调onHiddenChanged方法

Fragment2 onPause Fragment2 onStop Fragment2 onDestoryView Fragment2 onDestory

从Log中可以看出:

用hide + add方法切换,Fragment1在隐藏(hide)时并不会走onDestoryView,所以显示时也不会走onCreateView,所有View都一直保存在内存中。

使用replace方法的情况:

载入Fragmet1的生命周期与上面一致使用replace方法切换到Fragment2 FragmentTransaction ft = getFragmentManager().beginTransaction(); ft.replace(R.id.simple_fragment, Fragment2); ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN); ft.commit();

Fragment1和Fragment2的生命周期(顺序可能是两个Fragment回调混起来排列的):

Fragment1 onPause Fragment1 onStop Fragment1 onDestoryView Fragment1 onDestory Fragment2 onCreate Fragment2 onCreateView Fragment2 onStart Fragment2 onResume

从Log可以看出:

Fragment1被replace为Fragment2时先后走了onDestroyView和onDestroy方法,即此时Fragment1被回收了

使用replace方法返回Fragment1: FragmentTransaction ft = getFragmentManager().beginTransaction(); ft.replace(R.id.simple_fragment, Fragment1); ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN); ft.commit();

此时走过的生命周期:

Fragment1 onCreate Fragment1 onCreateView Fragment1 onStart Fragment1 onResume Fragment2 onPause Fragment2 onStop Fragment2 onDestoryView Fragment2 onDestory

从Log可以看出:

Fragment1因为已经被回收,又走onCreate,Fragment2被回收。即:每次replace都会有Fragment的销毁和创建!

以上就是两种方式切换Fragment的过程,总结起来就是:

使用hide + add方式添加Fragment时,旧的Fragment不会走任何生命周期,只会回调onHiddenChange方法。使用replace方式添加Fragment时,旧的Fragment会走onDestroy,即被完全销毁,重新切换回来的时候,再创建该Fragment,系统资源消耗比较严重

那么,理解了上述两种方式后,如果有以下需求:

想在Fragment显示和隐藏时注册和反注册某些监听。有人想到用第一种方式,但此处还有一个问题,就是在Fragment创建和销毁时,不会回调onHiddenChange方法,因此第一种方式Pass。第二种方式可以实现,但资源消耗太大,每次切换都伴随着Fragment的创建和销毁,也不太合适。

其实,FragmentManager还存在一个API:

addToBackStack(String tag)

其中tag为Fragment标签,用于标识特定Fragment。使用非常简单,只要在replace后,commit前加入该语句即可,例如:

FragmentTransaction ft = getFragmentManager().beginTransaction(); ft.replace(R.id.simple_fragment, Fragment1); //add - start getFragmentManager.addToBackStack(null); //add - end ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN); ft.commit();

当我们加上addToBackStack方法后,Fragment在被replace时,会走onDestroyView,而不走onDestroy;顶层Fragment出栈,该Fragment显示在顶端时,由于该Fragment之前没有被销毁,此时只会走onCreateView方法,这样就实现了上面的需求。

入栈有了,当我想恢复显示之前的Fragment该怎么办呢?与add相对应的API叫做:

popBackStack

如果你的Activity继承自FragmentActivity,此方法一般不需要自己调用,Activity在onBackPressed方法中已经做过处理,点击返回键即可实现依次退出Fragment栈。如果你想点击某个按钮实现退栈,那么调用该方法即可!


以上就是全部内容了,欢迎讨论及指正!

转载请注明原文地址: https://www.6miu.com/read-56153.html

最新回复(0)