github地址
一、简介
玩过微信的都知道,微信用的是懒加载的模式,之所以使用懒加载是因为:当使用viewpager+adapter作为应用大的布局时,viewpager会通过setOffscreenPageLimit来设置预加载的项目,不设置setOffscreenPageLimit,则默认为1(设置0无效,可以查看该方法源码知道),也就是当我们打开应用看到的时候fragmentOne时,实际上其他fragment(例如fragmentSecond)也进行了加载,只不过没有显示出来罢了,但是这样就造成了不必要的资源浪费(例如,fragmentSecond没有显示,但是却进行了大量的网络加载操作)。
在此先要说下一下几个方法:
1.ViewPager中的setOffscreenPageLimit方法,设置预加载的页面个数,参数不能小于1因为默认最小就是1。作用是:可以让Fragment视图不会被销毁。
2.Fragment中的setUserVisibleHint方法,当参数为true时对用户可见,当为false时对用户不可见(这是懒加载的关键所在)
二、使用步骤
1、LazyFragment:
/**
* A simple {@link Fragment} subclass.
* "懒加载"的Fragment的基类
*/
public abstract class LazyFragment extends Fragment {
private View view;
private boolean needInit; //是否需要在onCreateView中初始化组件
private boolean hasLoad; //标识是否已经加载过
private boolean hasCreated; //是否为第一次加载数据
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
//展示 & 没有加载过
if (isVisibleToUser && !hasLoad) {
//如果当前Fragment向用户展示且没有加载过,进行下一步判断
if (hasCreated) {
//如果onCreateView已经被创建,此时进行加载
initView();
} else {
//如果Fragment没有创建,那么设置标记,在onCreateView中加载
needInit = true;
}
}
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
view = inflater.inflate(getLayoutId(), container, false);
if (needInit) {
//是否要初始化,后面页不需要
initView();
needInit = false;
}
hasCreated = true;
return view;
}
private void initView() {
init(view);
hasLoad = true;
}
//获取Fragment的布局文件
@LayoutRes
protected abstract int getLayoutId();
//包含初始化数据
protected abstract void init(View view);
}
2、所有Fragment子类继承于LazyFragment
public class ShopCartFragment extends LazyFragment {
@Override
protected int getLayoutId() {
return R.layout.fragment_shop_cart;
}
//初始化View和数据
@Override
protected void init(View view) {
//初始化View
initView();
//初始化数据
initData();
}
3、Activity中注意
//设置预加载页面的数目,避免当页面个数 > 3时,有Fragment被销毁的情况
viewPager.setOffscreenPageLimit(mList.size() - 1);
4、另一个懒加载的Fragment的基类
public abstract class BaseFragment extends Fragment {
private boolean isVisible = false;//当前Fragment是否可见
private boolean isInitView = false;//是否与View建立起映射关系
private boolean isFirstLoad = true;//是否是第一次加载数据
private View convertView;
private SparseArray<View> mViews;
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
LogUtil.m("isVisibleToUser " + isVisibleToUser + " " + this.getClass().getSimpleName());
if (isVisibleToUser) {
isVisible = true;
lazyLoadData();
} else {
isVisible = false;
}
super.setUserVisibleHint(isVisibleToUser);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
LogUtil.m(" " + this.getClass().getSimpleName());
convertView = inflater.inflate(getLayoutId(), container, false);
mViews = new SparseArray<>();
initView();
isInitView = true;
lazyLoadData();
return convertView;
}
private void lazyLoadData() {
if (isFirstLoad) {
LogUtil.m("第一次加载 " + " isInitView " + isInitView + " isVisible " + isVisible + " " + this.getClass().getSimpleName());
} else {
LogUtil.m("不是第一次加载" + " isInitView " + isInitView + " isVisible " + isVisible + " " + this.getClass().getSimpleName());
}
if (!isFirstLoad || !isVisible || !isInitView) {
LogUtil.m("不加载" + " " + this.getClass().getSimpleName());
return;
}
LogUtil.m("完成数据第一次加载"+ " " + this.getClass().getSimpleName());
initData();
isFirstLoad = false;
}
/**
* 加载页面布局文件
* @return
*/
protected abstract int getLayoutId();
/**
* 让布局中的view与fragment中的变量建立起映射
*/
protected abstract void initView();
/**
* 加载要显示的数据
*/
protected abstract void initData();
/**
* fragment中可以通过这个方法直接找到需要的view,而不需要进行类型强转
* @param viewId
* @param <E>
* @return
*/
protected <E extends View> E findView(int viewId) {
if (convertView != null) {
E view = (E) mViews.get(viewId);
if (view == null) {
view = (E) convertView.findViewById(viewId);
mViews.put(viewId, view);
}
return view;
}
return null;
}
}