本文基于com.android.support:support-v4:26.1.0 分析android fragment分析。
fragment目前已经被广泛应用到app开发中,它的使用使得activity角色变为fragment的容器,调度fragment的添加显示和隐藏。fragment作为单独的功能模块,提高的模块化和可复用。
fragment具有使用场景包括:
多个fragment嵌套,点击当前fragment按钮进入下一个fragment
一个activity同时显示多个fragment
viewpager 分页显示多个fragment
但实际使用过程中往往会碰到getActivity()为null 导致app奔溃异常,网路请求回调fragment不存在导致异常奔溃等等恼人的问题。 因为我们需要深入理解fragment的生命周期。
PDMCpkV.png
当activity 持有一个fragment时:
点击进入
com.example.wenson.myfragmenttest I/Wen.Activity: onCreate
com.example.wenson.myfragmenttest I/Wen.FragmentOne: onAttach
com.example.wenson.myfragmenttest I/Wen.Activity: onAttachFragment
com.example.wenson.myfragmenttest I/Wen.FragmentOne: onCreate
com.example.wenson.myfragmenttest I/Wen.FragmentOne: onCreateView
com.example.wenson.myfragmenttest I/Wen.FragmentOne: onActivityCreated
com.example.wenson.myfragmenttest I/Wen.FragmentOne: onStart
com.example.wenson.myfragmenttest I/Wen.Activity: onResume
com.example.wenson.myfragmenttest I/Wen.FragmentOne: onResume
按back按键返回
com.example.wenson.myfragmenttest I/Wen.FragmentOne: onPause
com.example.wenson.myfragmenttest I/Wen.Activity: onPause
com.example.wenson.myfragmenttest I/Wen.FragmentOne: onStop
com.example.wenson.myfragmenttest I/Wen.Activity: onStop
com.example.wenson.myfragmenttest I/Wen.FragmentOne: onDestroyView
com.example.wenson.myfragmenttest I/Wen.FragmentOne: onDestroy
com.example.wenson.myfragmenttest I/Wen.FragmentOne: onDetach
com.example.wenson.myfragmenttest I/Wen.Activity: onDestroy
从上面的log分析总结:
和activity的交互必须在onActivityCreated执行之后调用,比如getContext(),getActivity()。
当在fragment执行异步请求回调时 比如网络请求时,如果需要UI更新时需要判断fragment的是否执行了onDestroyView。
在onCreateView里我们注册各种view的callback事件,在onDestroyView中我们需要移除各种view的callback事件。
当一个fragment onAttach后activity都会执行onAttachFragment(), 在activity里我们可以持有当前fragment的引用。但只适合场景1,不适合场景2,3.
在onSaveInstanceState中存储临时数据,在onCreate,onActivityCreated, onCreateView。获取临时数据,什么时候获取根据数据在什么生命周期中被使用。
什么时候调用setRetainInstance?
setRetainInstance(true)时,当旋转屏幕时,fragment实例不会被销毁,重建时将不执行onDestroy()和onCreate。注意:只使用旋转屏幕的场景下,后fragment后台退出内存不足被销毁时,仍然会被完全重建。
所以当你的fragment使用AsyncTask下载等需要耗时长的任务时这种场景下,你需要setRetainInstance(true),因为我们是在onCreate创建AsyncTask对象的,这样可以避免AsyncTask被销毁重建。
当前fragment界面点击进入下一个fragment,上一个fragment不会执行onHiddenChanged()?
com.example.wenson.myfragmenttest I/Wen.Activity: onCreate
com.example.wenson.myfragmenttest I/Wen.FragmentOne: onAttach
com.example.wenson.myfragmenttest I/Wen.Activity: onAttachFragment
com.example.wenson.myfragmenttest I/Wen.FragmentOne: onCreate
com.example.wenson.myfragmenttest I/Wen.FragmentOne: onCreateView
com.example.wenson.myfragmenttest I/Wen.FragmentOne: onActivityCreated
com.example.wenson.myfragmenttest I/Wen.FragmentOne: onStart
com.example.wenson.myfragmenttest I/Wen.Activity: onStart
com.example.wenson.myfragmenttest I/Wen.Activity: onResume
com.example.wenson.myfragmenttest I/Wen.FragmentOne: onResume
com.example.wenson.myfragmenttest I/Wen.FragmentTwo: onAttach
com.example.wenson.myfragmenttest I/Wen.Activity: onAttachFragment
com.example.wenson.myfragmenttest I/Wen.FragmentTwo: onCreate
com.example.wenson.myfragmenttest I/Wen.FragmentTwo: onCreateView
com.example.wenson.myfragmenttest I/Wen.FragmentTwo: onActivityCreated
com.example.wenson.myfragmenttest I/Wen.FragmentTwo: onStart
com.example.wenson.myfragmenttest I/Wen.FragmentTwo: onResume
从log分析进入下一个fragment后上一个fragment仍然是onResume状态。
我们可以将启动下一个fragment的方式修改为如下:
Fragment fragmentTwo = FragmentTwo.newInstance("","");
getSupportFragmentManager()
.beginTransaction()
.addToBackStack(FragmentTwo.TAG)
.add( R.id.content, fragmentTwo, FragmentTwo.TAG)
.hide(mCurrentFragment)
.commit();
修改后在第二个fragment界面按返回键后会回退到第一个fragment界面,并且会响应onHiddenChanged()。
一个activity同时显示多个fragment
com.example.wenson.myfragmenttest I/Wen.Activity: onCreate
com.example.wenson.myfragmenttest I/Wen.FragmentOne: onAttach
com.example.wenson.myfragmenttest I/Wen.Activity: onAttachFragment
com.example.wenson.myfragmenttest I/Wen.FragmentOne: onCreate
com.example.wenson.myfragmenttest I/Wen.FragmentTwo: onAttach
com.example.wenson.myfragmenttest I/Wen.Activity: onAttachFragment
com.example.wenson.myfragmenttest I/Wen.FragmentTwo: onCreate
com.example.wenson.myfragmenttest I/Wen.FragmentOne: onCreateView
com.example.wenson.myfragmenttest I/Wen.FragmentOne: onActivityCreated
com.example.wenson.myfragmenttest I/Wen.FragmentTwo: onCreateView
com.example.wenson.myfragmenttest I/Wen.FragmentTwo: onActivityCreated
com.example.wenson.myfragmenttest I/Wen.FragmentOne: onStart
com.example.wenson.myfragmenttest I/Wen.FragmentTwo: onStart
com.example.wenson.myfragmenttest I/Wen.Activity: onStart
com.example.wenson.myfragmenttest I/Wen.Activity: onResume
com.example.wenson.myfragmenttest I/Wen.FragmentOne: onResume
com.example.wenson.myfragmenttest I/Wen.FragmentTwo: onResume
按返回键退出
com.example.wenson.myfragmenttest I/Wen.FragmentOne: onPause
com.example.wenson.myfragmenttest I/Wen.FragmentTwo: onPause
com.example.wenson.myfragmenttest I/Wen.Activity: onPause
com.example.wenson.myfragmenttest I/Wen.FragmentOne: onStop
com.example.wenson.myfragmenttest I/Wen.FragmentTwo: onStop
com.example.wenson.myfragmenttest I/Wen.Activity: onStop
com.example.wenson.myfragmenttest I/Wen.FragmentOne: onDestroyView
com.example.wenson.myfragmenttest I/Wen.FragmentOne: onDestroy
com.example.wenson.myfragmenttest I/Wen.FragmentOne: onDetach
com.example.wenson.myfragmenttest I/Wen.FragmentTwo: onDestroyView
com.example.wenson.myfragmenttest I/Wen.FragmentTwo: onDestroy
com.example.wenson.myfragmenttest I/Wen.FragmentTwo: onDetach
com.example.wenson.myfragmenttest I/Wen.Activity: onDestroy
从log分析可知
● 如果有2个fragment,则 Activity: onAttachFragment 会被调用2次
● 2个fragment依次执行onAttach onCreate,
● 再依次执行 onCreateView onActivityCreated
Activity viewpager 2个fragment
com.example.wenson.myfragmenttest I/Wen.Activity: onCreate
com.example.wenson.myfragmenttest I/Wen.Activity: onStart
com.example.wenson.myfragmenttest I/Wen.Activity: onResume
com.example.wenson.myfragmenttest I/Wen.FragmentOne: onAttach
com.example.wenson.myfragmenttest I/Wen.Activity: onAttachFragment
com.example.wenson.myfragmenttest I/Wen.FragmentOne: onCreate
com.example.wenson.myfragmenttest I/Wen.FragmentTwo: onAttach
com.example.wenson.myfragmenttest I/Wen.Activity: onAttachFragment
com.example.wenson.myfragmenttest I/Wen.FragmentTwo: onCreate
com.example.wenson.myfragmenttest I/Wen.FragmentOne: onCreateView
com.example.wenson.myfragmenttest I/Wen.FragmentOne: onActivityCreated
com.example.wenson.myfragmenttest I/Wen.FragmentOne: onStart
com.example.wenson.myfragmenttest I/Wen.FragmentOne: onResume
com.example.wenson.myfragmenttest I/Wen.FragmentTwo: onCreateView
com.example.wenson.myfragmenttest I/Wen.FragmentTwo: onActivityCreated
com.example.wenson.myfragmenttest I/Wen.FragmentTwo: onStart
com.example.wenson.myfragmenttest I/Wen.FragmentTwo: onResume
从log分析:
Activity viewpager 持有多个2个fragment 时,Acvitity 与fragment的生命周期不相关了
总结:
在不同场景下activity和fragment的生命周期可能不同,所以我们需要理解之间的差异,在fragment正确的生命周期中处理好异步调用,数据存储等操作。
代码实例:
https://github.com/wensonli/MyFragmentTest