ViewPager+Fragment预加载问题处理

ViewPager+Fragment结合使用的时候,当前显示的fragment的左右两边的fragment也会被创建,在viewPager里面有个方法setOffscreenPageLimit是设置预加载的fragment数目:

/**
Set the number of pages that should be retained to either side of the
      current page in the view hierarchy in an idle state. Pages beyond this
     limit will be recreated from the adapter when needed.

设置视图层次结构中处于空闲状态时应保留到当前页任一侧的页数。超过此限制的页将在需要时从适配器重新创建。
**/
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();
        }
    }

这个方法里面,至少要预加载左右边(如果有)各一个fragment。

也就是说,viewpager一定会预先创建当前页面两边还未可见的fragment。

那么看下fragment的生命周期和setUserVisibleHint()这个方法的调用顺序:

setUserVisibleHint():设置Fragment可见或者不可见时会调用此方法。在该方法里面可以通过调用getUserVisibleHint()获得Fragment的状态是可见还是不可见的,如果可见则进行懒加载操作。

onAttach():执行该方法时,Fragment与Activity已经完成绑定,该方法有一个Activity类型的参数,代表绑定的Activity,这时候你可以执行诸如mActivity = activity的操作。

onCreate():初始化Fragment。可通过参数savedInstanceState获取之前保存的值。

onCreateView():初始化Fragment的布局。加载布局和findViewById的操作通常在此函数内完成,但是不建议执行耗时的操作,比如读取数据库数据列表。

onActivityCreated():执行该方法时,与Fragment绑定的Activity的onCreate方法已经执行完成并返回,在该方法内可以进行与Activity交互的UI操作,所以在该方法之前Activity的onCreate方法并未执行完成,如果提前进行交互操作,会引发空指针异常。

onStart():执行该方法时,Fragment由不可见变为可见状态。

onResume():执行该方法时,Fragment处于活动状态,用户可与之交互。

onPause():执行该方法时,Fragment处于暂停状态,但依然可见,用户不能与之交互。

onSaveInstanceState():保存当前Fragment的状态。该方法会自动保存Fragment的状态,比如EditText键入的文本,即使Fragment被回收又重新创建,一样能恢复EditText之前键入的文本。

onStop():执行该方法时,Fragment完全不可见。

onDestroyView():销毁与Fragment有关的视图,但未与Activity解除绑定,依然可以通过onCreateView方法重新创建视图。通常在ViewPager+Fragment的方式下会调用此方法。

onDestroy():销毁Fragment。通常按Back键退出或者Fragment被回收时调用此方法。

onDetach():解除与Activity的绑定。在onDestroy方法之后调用。

Fragment生命周期执行流程(注意红色的不是生命周期方法):

Fragment创建:setUserVisibleHint()->onAttach()->onCreate()->onCreateView()->onActivityCreated()->onStart()->onResume();

Fragment变为不可见状态(锁屏、回到桌面、被Activity完全覆盖):onPause()->onSaveInstanceState()->onStop();

Fragment变为部分可见状态(打开Dialog样式的Activity):onPause()->onSaveInstanceState();

Fragment由不可见变为活动状态:onStart()->OnResume();

Fragment由部分可见变为活动状态:onResume();

退出应用:onPause()->onStop()->onDestroyView()->onDestroy()->onDetach()
(注意退出不会调用onSaveInstanceState方法,因为是人为退出,没有必要再保存数据);

Fragment被回收又重新创建:
被回收执行 onPause()->onSaveInstanceState()->onStop()->onDestroyView()->onDestroy()->onDetach(),
重新创建执行 onAttach()->onCreate()->onCreateView()->onActivityCreated()->onStart()->onResume()->setUserVisibleHint();

横竖屏切换:与Fragment被回收又重新创建一样。

fragment 预创建 --》滑动过去--》再划回来:          

逐步滑过来,预创建:
setUserVisibleHint-->onAttach-->onCreate-->onCreateView--> onActivityCreated -->
onStart--> onResume --> setUserVisibleHint

逐步划过去:
setUserVisibleHint -->onPause-->onStop-->onDestroyView

逐步划回来:
setUserVisibleHint -->onCreateView-->onActivityCreated-->onStart-->onResume

如果我们不需要预加载的时候创建还未可见的fragment的对象,生成这里面的数据占用太多内存的话,可以结合setUserVisibleHint(boolean isVisibleToUser)这个方法,设置当fragment可见的时候才加载相关数据。这种叫做懒加载,等UI需要展示给用户的时候,才去加载数据,而不是提前加载好,可以提高activity的初始化速度,节省用户的流量。

需要注意的是:如果懒加载的数据要结合UI进行填充展示的话,一定要判断onCreateView()执行完毕,UI控件都加载进来了才能绑定数据,不然会报空指针异常。因为结合上面的生命周期的执行流程可以看到setUserVisibleHint这个方法的执行顺序可能在onCreateVIew前面,加两个布尔型的判断值就可以了。

通常写一个fragment的基类,在基类里面处理好懒加载的判断过程,提供抽象方法给子类fragment再进行相关懒加载操作。

public abstract class BaseFragment extends Fragment {

    private boolean isCreateView = false;

    private boolean isUserVisable = false;

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        isCreateView = true;
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (isCreateView && isVisibleToUser) {
            lazyLoad();
        }
    }

    protected abstract void lazyLoad();
}

参考:简书的一篇文章

猜你喜欢

转载自blog.csdn.net/hpp_1225/article/details/88815376