Fragment 的懒加载

本文介绍了Fragment懒加载的概念及其实现方式。懒加载是指当Fragment的UI对用户可见时才加载数据,以提高性能。通过使用setUserVisibleHint方法判断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.

所以,只需要判断参数 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

可以看到 setUserVisibleHint 的执行顺序是

setUserVisibleHint(false) -> onAttach -> onCreate -> setUserVisibleHint(true)  -> onCreateView -> onActivityCreated ->.... -> onDetach

代码

为了方便,封装一个基类 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();
}

等等,为什么 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();
    }
}

limit 默认为 1 ,就算传一个 0 也无济于事啊。

总结

  • 懒加载的技术关键点
  • setUserVisibleHint 的执行顺序
  • 为什么 ViewPager.setOffscreenPageLimit(0) 无效?

参考来源



文/程序猴(简书作者)
原文链接:file:///D:/360%E6%9E%81%E9%80%9F%E6%B5%8F%E8%A7%88%E5%99%A8%E4%B8%8B%E8%BD%BD/wangye/Fragment%20%E7%9A%84%E6%87%92%E5%8A%A0%E8%BD%BD%20-%20%E7%AE%80%E4%B9%A6.html
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
### 实现Fragment懒加载的方法 在 Android 中,`Fragment` 的懒加载可以通过多种方式实现。当 `Fragment` 被创建并附加到活动 (`Activity`) 上时,默认情况下会立即初始化其视图和其他资源。然而,在某些场景下,可能希望延迟这些操作直到 `Fragment` 变得可见给用户。 对于使用 `FragmentPagerAdapter` 和 `ViewPager` 组合的情况,可以利用生命周期回调来控制何时真正启动数据获取或其他耗时的任务[^1]。具体来说: - 当页面首次被选中时调用 `setUserVisibleHint(boolean isVisibleToUser)` 方法;如果当前页变为可见,则参数为 true 否则 false。 ```java @Override public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); if (isVisibleToUser && isViewInitiated){ loadData(); } } ``` 另一种常见的方式是在 `onHiddenChanged()` 函数里处理懒加载逻辑。这适用于那些已经在屏幕上显示过一次但是后来又被隐藏起来再重新显现出来的片段实例。一旦检测到状态变化为不再隐藏(`hidden==false`)就可以触发相应的业务流程了[^2]: ```java @Override public void onHiddenChanged(boolean hidden) { super.onHiddenChanged(hidden); if (!hidden){ // 执行懒加载操作 lazyLoadData(); } } ``` 除了上述两种基本模式外,在更复杂的应用结构里面如多层嵌套布局(例如多个 `Fragment` 或者 `ViewPager`),开发者还需要考虑不同层次之间的交互影响以及如何有效地管理各个组件间的依赖关系[^3]。 为了确保最佳性能和用户体验,建议只在确实必要的时候才去请求网络或者读取本地存储中的大文件等内容,并且要合理安排好异步任务以免阻塞主线程造成界面卡顿现象发生。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值