首先定义一个基类Fragment,重写所有生命周期方法,并打印log.
假如现在有五个子类Fragment通过ViewPager左右滑动切换.
刚进入页面时:
first----------setUserVisibleHint: false
second---------setUserVisibleHint: false
first----------setUserVisibleHint: true
first----------onAttach
first----------onCreate
second----------onAttach
second----------onCreate
first-----------onCreateView
first-----------onActivityCreated
first-----------onStart
first-----------onResume
second-----------onCreateView
second-----------onActivityCreated
second-----------onStart
second-----------onResume
ViewPager默认预先加载一个Fragment.当Fragment对用户可见时,setUserVisibleHint
参数为true,否则为false.
从上面的log可以看到,初始化页面时,预先走了第二个fragment的setUserVisibleHint
方法,但是此时所有的fragment对用户还不可见,所以两个setUserVisibleHint
的参数都为false.当第一个fragment对用户可见时,继续走了setUserVisibleHint
,参数为true,而第二个fragment对用户不可见,参数为false,就没有再次走setUserVisibleHint
.而后是交替加载两个fragment的生命周期直到onResume,从这里可以看出onResume不能判定fragment是否对用户可见.
所以可以在setUserVisibleHint
中根据其参数判定某个Fragment是否对用户可见.
然后滑动,使第二个fragment可见,隐藏第一个fragment.其生命周期流程如下:
third-----------setUserVisibleHint: false
first-----------setUserVisibleHint: false
second-----------setUserVisibleHint: true
third----------onAttach
third----------onCreate
third-----------onCreateView
third-----------onActivityCreated
third-----------onStart
third-----------onResume
同样地,先将下一个fragment和上一个frag的setUserVisibleHint
的参数重置为false,再将自身的置为true,上面的结论是正确的.并且初始化下一个fragment的生命周期,并没有销毁上一个fragment的生命周期,同时也没有再走自己别的生命周期方法.
从第二个fragment滑动到第三个fragment,生命周期流程如下:
forth-----------setUserVisibleHint: false
second-----------setUserVisibleHint: false
third-----------setUserVisibleHint: true
forth----------onAttach
forth----------onCreate
first-----------onPause
first-----------onStop
first-----------onDestroyView
forth-----------onCreateView
forth-----------onActivityCreated
forth-----------onStart
forth-----------onResume
在这里销毁了第一个fragment的view,走到了onDestroyView
.
fragment滑动切换时,会销毁相隔前一个的view,这个相隔前一个不是位置上的相隔前一个,而是时间上的(其实是fragment任务管理栈,先进先出).
总结以上的结论:
1:通过setUserVisibleHint的参数来判断当前fragment是否可见.
2:滑动切换到某个fragment,会预加载下一个fragment的生命周期,销毁相隔前一个的fragment的view(onDestroyView),并且将自己的setUserVisibleHint参数置为true,不会再走自己的生命周期方法(被前一个fragment预加载了).
懒加载
这里所说的懒加载就是只有当前fragment处于可见时,才加载数据,否则不加载.fragment默认是预加载下一个页面数据的.
从上面来看,是不是只要在setUserVisibleHint
中根据参数来判断是否加载数据就可以了?不是的,要考虑到当前页面的View是否加载完成.
定义一个成员变量,来标记view是否创建完成
boolean isViewCreated = false;
在onCreateView中将isViewCreated置为true,onDestroyView中置为false.
初始化页面时,第一个Fragment
的setUserVisibleHint
参数为true时,其onCreateView方法还没走到,变量isViewCreated = false.这时我们在onActivityCreated中做加载数据的判断
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState){
super.onActivityCreated(savedInstanceState);
if(isViewCreated && getUserVisibleHint()){
loadData();
}
}
当滑动到下一个页面时,不会再次走这个页面的生命周期方法,并且其onCreateView方法已经加载完毕,所以在setUserVisibleHint中做加载数据
@Override
public void setUserVisibleHint(boolean isUserVisibleHint){
if(isUserVisibleHint && isViewCreated){
loadData();
}
}
关闭懒加载
定义一个boolean
字段来开启/关闭懒加载
/*是否开启懒加载,默认开启*/
protected boolean useLazyMode = true;
需要在onActivityCreated
和setUserVisibleHint
中处理数据加载.
@Override
public void setUserVisibleHint(boolean isUserVisibleHint){
if(isUserVisibleHint && isViewCreated&&useLazyMode ){
loadData();
}
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState){
super.onActivityCreated(savedInstanceState);
if (useLazyMode){
//当前页面可见时才去加载数据
if (isViewCreated&&getUserVisibleHint()){
loadData();
}
}else {
//预加载下一个页面数据
if (isViewCreated){
loadData();
}
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。