1.什么是懒加载
懒加载是指按需/延迟加载,例如App中的资讯展示界面(一般会使用ViewPager+Fragment实现),常常会包含多个主题,考虑到节省用户流量/加快响应速度/减小服务器并发压力等等因素,一般会要求当切换至某一主题时才加载该主题对应的数据。
而ViewPager默认会保存当前页左右两边任意一侧一页的界面(通过ViewPager的setOffscreenPageLimit(int limit)方法设置,默认最小值为1),因此进入资讯界面时至少会初始化两个Fragment,与功能要求不符,这时就需要用到Fragment的懒加载技术
2.如何实现懒加载
查询资料可知,通过Fragment的setUserVisibleHint(boolean isVisibleToUser)方法可以判断当前fragment是否对用户可见,当isVisibleToUser为true时,加载数据,否则不加载数据。该方法的注释中还有一段提示:
* Note: This method may be called outside of the fragment lifecycle.
* and thus has no ordering guarantees with regard to fragment lifecycle method calls.
翻译一下,该方法或许会在Fragment的生命周期之外被调用,因此对于Fragment生命周期方法调用没有顺序保证,即调用该方法时,可能还没有执行Fragment的onCreateView()方法,如果此时执行加载数据操作,可能引起空指针异常,因此还需要在onCreateView()方法中进行一次判断。
另外还需要注意一点,setUserVisibleHint(boolean isVisibleToUser)方法在FragmentPagerAdapter和FragmentStatePagerAdapter中被调用,因此如果需要实现懒加载,ViewPager使用的Adapter必须是这两个Adapter的子类。
3.代码示例
3.1覆写setUserVisibleHint方法
/**
* Fragment是否对用户可见,可见时才加载数据
*/
private boolean isUIVisiable = false;
/**
* setUserVisibleHint有可能在onCreateView之前调用,故需确保View已创建后再加载数据
*/
private boolean isViewCreated = false;
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
Log.e(TAG, "isVisibleToUser " + isVisibleToUser);
if (isVisibleToUser) {
isUIVisiable = true;
//ViewPager会缓存至少相邻一页Fragment,当切换Fragment时,会调用setUserVisibleHint方法
//这里再次触发懒加载
lazyLoad();
} else {
isUIVisiable = false;
}
}
3.2覆写onCreateView方法
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_simple, container, false);
...
isViewCreated = true;
lazyLoad();
return binding.getRoot();
}
3.3添加lazyLoad方法
private void lazyLoad() {
Log.e(TAG, "isUIVisiable " + isUIVisiable + " isViewCreated " + isViewCreated);
if (isUIVisiable && isViewCreated) {
isUIVisiable = false;
isViewCreated = false;
getData();
}
}
在getData()方法中执行具体数据加载逻辑
3.4新建Adapter
private class SimpleFragmentPagerAdapter extends FragmentPagerAdapter {
private List mListFragment;
public SimpleFragmentPagerAdapter(FragmentManager fm, List fragmentList) {
super(fm);
mListFragment = fragmentList;
}
@Override
public Fragment getItem(int position) {
return mListFragment.get(position);
}
@Override
public int getCount() {
return mListFragment == null ? 0 : mListFragment.size();
}
}
3.5在Activity中使用
private void initViewPager() {
List fragmentList = new ArrayList<>();
fragmentList.add(LazyLoadFragment.newInstance(ContextCompat.getColor(this, R.color.colorPrimaryDark)));
fragmentList.add(LazyLoadFragment.newInstance(ContextCompat.getColor(this, R.color.color_86d0ab)));
fragmentList.add(LazyLoadFragment.newInstance(ContextCompat.getColor(this, R.color.color_fb9b10)));
fragmentList.add(LazyLoadFragment.newInstance(ContextCompat.getColor(this, R.color.colorAccent)));
binding.viewPager.setOffscreenPageLimit(3);
SimpleFragmentPagerAdapter adapter = new SimpleFragmentPagerAdapter(getSupportFragmentManager(), fragmentList);
binding.viewPager.setAdapter(adapter);
}