Fragment 的懒加载
-
Fragment 懒加载是什么意思?
所谓懒加载,即Fragment 的 UI 对用户可见时才加载数据。以前我没啥经验,一股脑的从服务器拉取数据之后立马把数据绑定到 Fragment 的 UI 组件上,导致性能低下。后来知道了这一技术,才明白这才是移动端加载数据的正确姿势。
懒加载的技术关键点是什么?
根据定义:所谓懒加载,即Fragment 的 UI 对用户可见时才加载数据。
需要判断何时 Fragment 的 UI 才对用户可见如何判断 Fragment 的 UI 是否对用户可见?
Fragment 提供了一个方法 public void setUserVisibleHint(boolean isVisibleToUser),API 的注释如下Set a hint to the system about whether this fragment's UI is currently visible to the user. This hint defaults to true and is persistent across fragment instance state save and restore- 1
- 2
所以,只需要判断参数 isVisibleToUser 是否为 True 即可知道该 Fragment 的 UI 是否对用户可见。
setUserVisibleHint 在什么时候调用?
对于单个 Fragment,setUserVisibleHint 是不会被调用的,只有该 Fragment 在 ViewPager 里才会被调用。所以,我写了一个 ViewPager + Fragment 的 Demo,打印了一下 Log。D/Owen_TestFragment: setUserVisibleHint: isVisibleToUser = false D/Owen_TestFragment: onAttach D/Owen_TestFragment: onCreate D/Owen_TestFragment: setUserVisibleHint: isVisibleToUser = true D/Owen_TestFragment: onCreateView D/Owen_TestFragment: onActivityCreated D/Owen_TestFragment: onStart D/Owen_TestFragment: onResume D/Owen_TestFragment: onPause D/Owen_TestFragment: onPause D/Owen_TestFragment: onStop D/Owen_TestFragment: onDestroyView D/Owen_TestFragment: onDestroy D/Owen_TestFragment: onDetach- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
可以看到 setUserVisibleHint 的执行顺序是:
setUserVisibleHint(false) -> onAttach -> onCreate -> setUserVisibleHint(true) -> onCreateView -> onActivityCreated ->.... -> onDetach- 1
代码
为了方便,封装一个基类 LazyLoadFragment,提供一个 loadData() 方法供调用去加载数据public abstract class LazyLoadFragment extends Fragment { /** * 控件是否初始化完成 */ private boolean isViewCreated; /** * 数据是否已加载完毕 */ private boolean isLoadDataCompleted; @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(getLayout(), container, false); initViews(view); isViewCreated = true; return view; } public abstract int getLayout(); public abstract void initViews(View view); @Override public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); if (isVisibleToUser && isViewCreated && !isLoadDataCompleted) { isLoadDataCompleted = true; loadData(); } } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); if (getUserVisibleHint()) { isLoadDataCompleted = true; loadData(); } } /** * 子类实现加载数据的方法 */ public abstract void loadData(); }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
等等,为什么 loadData() 会在两个地方执行?在 setUserVisibleHint 方法里执行我还能理解,为什么 onActivityCreated 也要执行呢?
因为,ViewPager 默认显示第一页,第一页肯定要先加载数据啊,而且 setUserVisibleHint 的执行顺序又是在 onCreatView 之前,同时 onCreatView 需要初始化界面和修改 isViewCreated 的值。所以就需要在 onActivityCreated 里执行一次咯。
等等
文章写到这里,我听到了一个不同的声音ViewPager 不是有 setOffscreenPageLimit(int limit) 方法吗?我调用 viewPager.setOffscreenPageLimit(0) 不就行了吗?
我想说:思路是对的,但是这样做没效果。为什么?看一下 setOffscreenPageLimit 的方法实现就知道了private static final int DEFAULT_OFFSCREEN_PAGES = 1; public void setOffscreenPageLimit(int limit) { if (limit < DEFAULT_OFFSCREEN_PAGES) { Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to " + DEFAULT_OFFSCREEN_PAGES); limit = DEFAULT_OFFSCREEN_PAGES; } if (limit != mOffscreenPageLimit) { mOffscreenPageLimit = limit; populate(); } }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
limit 默认为 1 ,就算传一个 0 也无济于事啊。
总结
懒加载的技术关键点
setUserVisibleHint 的执行顺序
为什么 ViewPager.setOffscreenPageLimit(0) 无效?
参考来源
tablayout+viewpager+fragment组合使用以及懒加载机制http://yaohepeng.com/2015/10/09/tablayout+viewpager+fragment组合使用以及懒加载机制/
版权声明:本文为博主原创文章,未经博主允许不得转载。

浙公网安备 33010602011771号