0%

Fragment懒加载

一、引入

  1. 在项目中应该经常会用到ViewPager+Fragment来显示界面,但是ViewPager会有预加载,这样的话有些东西会无法把控,还有就是刚进入App时可能会一次请求多个接口,在显示上可能会造成某些不可预知的问题,虽然可以禁用掉预加载,但是目前据我所知用得较多的方式是修改ViewPager的源码,而且这个源码并不是最新版本,禁用后也不会缓存已加载过的页面,这样滑动时可能在用户体验上有些不友善。

  2. Fragment有一个setUserVisibleHint(boolean isVisibleToUser)方法,他可以监听当前页面是否在前台,但是他会在onCreateView方法之前执行,这样的话因为此时布局还没有加载,所以可能会引发NullPointException导致程序Crash,在这里记录下如何使用setUserVisibleHint进行懒加载并且避免程序Crash。

二、Fragment懒加载

  1. 首先介绍一下这个方法:public void setUserVisibleHint(boolean isVisibleToUser),该方法用于告诉系统,这个Fragment的UI是否是可见的。所以我们只需要继承Fragment并重写该方法,即可实现在fragment可见时才进行数据加载操作,即Fragment的懒加载。

  2. 代码如下:

    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
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    /**
    * 标志已经初始化完成。
    */
    protected boolean isPrepared;
    /**
    * 当前界面是否可见
    */
    protected boolean isVisible;
    /**
    * 当前是否加载过,避免重复加载(缓存,可选操作,有些情况加入反而会引发Bug)
    */
    protected boolean isLoad = false;

    ------

    /**
    * Fragment的UI是否是可见
    * <p>
    * 在onCreateView方法之前调用
    *
    * @param isVisibleToUser
    */
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if (isVisibleToUser) {
    // 当前页面可见
    isVisible = true;
    lazyLoad();
    } else {
    // 当前页面不可见
    isVisible = false;
    }
    }

    ------

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    initInject();
    ... ...
    // 界面加载完成
    isPrepared = true;
    lazyLoad();
    }

    ------

    protected void lazyLoad() {
    // 状态判断,不符合不执行
    if (!isPrepared || !isVisible || isLoad) {
    return;
    }
    // 加载数据
    mPresenter.initData(url, pageId++);
    // 表示已经加载过
    isLoad = true;
    }

    ------

    @Override
    public void onDestroyView() {
    // 经过测试,当Fragment页面被销毁后如果继续在ViewPager滑过去重新显示了页面依然不加载
    // 状态还没变更过来,所以要在此处修改加载状态,表示本页没有加载过
    isLoad = false;
    // 视图销毁
    isPrepared = false;
    super.onDestroyView();
    }
  3. 不可以使用缓存的情况

我在Fragment所依附的Activity中的Toolbar中加了一个menu按钮,打算在Fragment中处理这个按钮的事件,使用默认的预加载会有一个Bug,即点击当前menu,但是menu所做的处理并不是当前可见的Fragment的menu,而是预加载页面的,也就是说点击比较混乱,处理的事件也不是我们想要处理的,这种情况如果添加了上述的懒加载,如果使用缓存的话,这样滑动过去之后在划回来menu的事件并没有刷新,所以说仍然会混乱。

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
@Override
protected void lazyLoad() {
if (!isPrepared || !isVisible || isLoad) {
return;
}
initMenuClick();
// 不缓存
// isLoad = true;
}

/**
* 使用Activity中toolbar的menu
*/
private void initMenuClick() {
ShowImageActivity activity = (ShowImageActivity) getActivity();
Toolbar toolbar = activity.toolbar;
toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_save:
saveImage();
break;
}
return true;
}
});
}

三、致谢&源码

我的例子:https://github.com/sdwfqin/MicroText

感谢CSDN貌似掉线的文章:http://blog.csdn.net/maosidiaoxian/article/details/38300627