在实际开发中,Fragment使用经常会结合viewpager一起使用,页面可能会由三个或更多Fragment构成,ViewPager有个预加载机制,加载的时候默认会把当前可见的Fragment俩边的Fragment同时加载进来,只有所有界面都加载完毕,当前可见的Fragment才会显示。这样子就会引发一个问题:如下图当我启动app的时候当前可见的Fragment是首页,但是ViewPager预加载机制也会加载小视频Fragment,但是我在小视频这个fragment生命周期中进行了几秒的耗时操作,这就会导致我进入首页的时候很慢,因为app要等首页和小视频这俩个fragment同时加载完毕才会显示。
上图只是我为了测试手动打的一个Thread.sleep();
但是日常我们所使用的app肯定会有一些网络请求操作,这些是比较耗时的,如果处理不好很影响用户体验。所于出现了fragment懒加载这个概念,对于懒加载,通俗点讲就是看不见的先不加载,当需要时再进行加载,让体验(页面绘制)、流量等更节省。就好比下图我只加载首页,小视频的我先不加载,你点开了我在加载,这样子进入首页很快。
setUserVisibleHint(boolean b)
这个方法在Fragment的生命周期里oncreate()方法之前会调用,作用是设置Fragment是否可见,切换Fragment的时候也会调用,通过getUserVisibleHint()返回的值我们可以知道Fragment是否可见。
在BaseFragment里设置三个标识:
isFragmentVisible :Fragment是否可见,默认false,不可见
isActivityPrepared :Activity是否加载完毕,默认false
isDataFirstInit :是否是第一次加载,默认true
//是否可见
protected Boolean isFragmentVisible = false;
//activity是否初始化完成
protected boolean isActivityPrepared = false;
//是否是第一次加载
protected boolean isDataFirstInit = true;
@Override
public void setUserVisibleHint(boolean isFragmentVisibleToUser) {
super.setUserVisibleHint(isFragmentVisibleToUser);
Log.e("TAG", "setUserVisibleHint");
if (isFragmentVisibleToUser == true) {//当可见的时候执行操作
isFragmentVisible = true;
loadData();
} else {//不可见时执行相应的操作
isFragmentVisible = false;
onInvisible();
}
}
根据setUserVisibleHint()传进来的参数去改变isFragmentVisible 的值,然后执行我们加载数据的方法loadDate()
当onActivityCreated()完成时设置isFragmentVisible为true,然后执行loadDate();
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log.e("TAG", "onActivityCreated");
isActivityPrepared = true;
loadData();
}
loadDate()只是一个入口,真正加载数据的方法是lazyLoad(),它是一个抽象方法,由我们的子类具体实现。在loadDate()方法中我们主要去判断这三个标识,当且仅当Fragment可见+Activity初始化完毕+第一次加载时才会执行我们的耗时操作,同时改变isDataFirstInit为false
其中添加isActivityPrepared 这个标识的原因是因为setUserVisibleHint()方法是在oncreate()之前执行的,如果我们的view初始化都还没开始就执行lazyLoad()加载数据,就会爆异常。
protected void loadData() {
//当fragment可见、activity初始化完成、第一次加载时执行
if (isActivityPrepared && isFragmentVisible && isDataFirstInit) {
isDataFirstInit = false;
lazyLoad();
}
}
protected abstract void lazyLoad();//子类实现
/**
* @Author: david.lvfujiang
* @Date: 2019/10/25
* @Describe:
*/
public abstract class MyBaseFragment extends Fragment {
//是否可见
protected Boolean isFragmentVisible = false;
//activity是否初始化完成
protected boolean isActivityPrepared = false;
//是否是第一次加载
protected boolean isDataFirstInit = true;
protected View mRootView;
protected Activity mActivity;
/**
* 在这里实现Fragment数据的缓加载.
* 初始化和切换的时候都会调用它
*
* @param isFragmentVisibleToUser
*/
@Override
public void setUserVisibleHint(boolean isFragmentVisibleToUser) {
super.setUserVisibleHint(isFragmentVisibleToUser);
Log.e("TAG", "setUserVisibleHint");
if (isFragmentVisibleToUser == true) {//当可见的时候执行操作
isFragmentVisible = true;
loadData();
} else {//不可见时执行相应的操作
isFragmentVisible = false;
onInvisible();
}
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.e("TAG", "onCreate");
this.mActivity = getActivity();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mRootView = inflater.inflate(getContentViewId(), container, false);
Log.e("TAG", "onCreateView");
return mRootView;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log.e("TAG", "onActivityCreated");
isActivityPrepared = true;
initData();
loadData();
}
protected abstract void initData();
protected abstract int getContentViewId();
protected abstract void lazyLoad();//子类实现
@Override
public void onDestroyView() {
super.onDestroyView();
}
/**
* 懒加载
*/
protected void loadData() {
//当fragment可见、activity初始化完成、第一次加载时执行
if (isActivityPrepared && isFragmentVisible && isDataFirstInit) {
isDataFirstInit = false;
lazyLoad();
}
}
protected void onInvisible() {
}
}
/**
* @Author: david.lvfujiang
* @Date: 2019/10/25
* @Describe:
*/
public class Fragment1 extends MyBaseFragment {
TextView textView;
@Override
protected int getContentViewId() {
return R.layout.fragment1_layout;
}
@Override
protected void lazyLoad() {
Log.e("fragment1", "fragment1");
try {
Thread.sleep(2000);
textView.setText("哈哈哈哈");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
protected void initData() {
textView = mRootView.findViewById(R.id.text_name);
}
}