共计 2748 个字符,预计需要花费 7 分钟才能阅读完成。
首先定义一个基类 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 预加载了).
懒加载
是不是只要在 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();
}
}
//todo 下一步处理页面不可见时, 取消数据加载