在Android开发中常常会使用到ViewPager, ViewPager若是和Fragment一块儿使用的话, 就要考虑懒加载和预加载的问题. ViewPager有个方法setOffscreenPageLimit 这个方法能够配置缓存数量. 那是否是直接设置0就能够实现懒加载了呢? 不是的, 查看源码:git
public void setOffscreenPageLimit(int limit) {
if (limit < DEFAULT_OFFSCREEN_PAGES) { //DEFAULT_OFFSCREEN_PAGES为1
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();
}
}
复制代码
设置0后会无效的, limit 仍是被设置成默认的1github
懒加载就是当用户滑动到当前的frament才能去加载数据, 这样避免加载了数据可是没有使用到, 形成了浪费.
预加载是为了提早加载数据, 让用户减小等待时间. 懒加载和预加载应该根据具体的业务要求去使用. 没有谁好谁坏之分. 但二者的前提都是要搞清楚Fragment在ViewPager中的生命周期, 下面先来弄清楚生命周期的调用.缓存
首先写一个简单的Activity里面有ViewPager 代码以下:bash
public class MainActivity extends AppCompatActivity {
private ViewPager viewById;
private List<Fragment> list;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewById = findViewById(R.id.vp);
list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
SimpleFragment simpleFragment = SimpleFragment.newInstance(i);
list.add(simpleFragment);
}
MineAdapter mineAdapter = new MineAdapter(getSupportFragmentManager(),list);
viewById.setOffscreenPageLimit(1);
viewById.setAdapter(mineAdapter);
}
}
复制代码
关于这个SimpleFragment代码就不用贴出来了 很简单就是在各个生命周期中加入log. 这个MineAdapter 很简单的. 以下:网络
public class MineAdapter extends FragmentPagerAdapter {
List<Fragment> mPages;
public MineAdapter(FragmentManager fm, List<Fragment> pages) {
super(fm);
mPages=pages;
}
@Override
public Fragment getItem(int i) {
return mPages.get(i);
}
@Override
public int getCount() {
return mPages.size();
}
}
复制代码
运行程序 来看看Fragment生命周期 日志以下: 为了方便叙述第0个fragement简称为0号. 这时候实际上是缓存数量为1ide
经过以上的日志 能够总结关键几点.ui
懒加载是滑动到当前Fragment的时候才去调用的方法. 通常在实际业务中就是滑到了要展现的页面去调接口获取数据.
写一个基础的BaseLazyFragment , 继承这个BaseLazyFragment 重写lazyInit()方法. 这个方法里写你须要执行的懒加载操做.spa
public class BaseLazyFragment extends Fragment {
private boolean isViewPrepared; // 标识fragment视图已经初始化完毕
private boolean hasFetchData; // 标识已经触发过懒加载数据
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
lazyFetchDataIfPrepared(); //通过了预加载页面, 而后展现
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
isViewPrepared = true;
lazyFetchDataIfPrepared(); //首次进入, 没有预加载直接加载数据
}
/**
* 懒加载方法,获取数据什么的放到这边来使用,在切换到这个界面时才进行网络请求
*/
private void lazyFetchDataIfPrepared() {
// 用户可见fragment && 没有加载过数据 && 视图已经准备完毕
if (getUserVisibleHint() && !hasFetchData && isViewPrepared) {
hasFetchData = true; //已加载过数据
lazyInit();
}
}
/**
* 执行须要懒加载的方法
*/
protected void lazyInit() {
Log.i("zmin........." + getArguments().getInt("key"), ".............加载完成数据");
}
@Override
public void onDestroyView() {
super.onDestroyView();
hasFetchData = false;
isViewPrepared = false;
Log.i("zmin........." + getArguments().getInt("key"), ".............onDestroyView");
}
}
复制代码
viewpager其实对预加载有很好的支持. 能够直接调用方法setOffscreenPageLimit来设置缓存的数量.3d
在实际业务中, 可能存在这样一种需求. 虽然是须要预加载的, 可是要监听Fragment的可见状态. 好比Fragment中有视频播放. 若是Fragment可见的话就要播放. 不可见的时候就须要暂停. 这时候还须要考虑的是Fragment可能会跳转到其余界面. Fragment虽然可见和不可见有个生命周期方法setUserVisibleHint回调, 可是没法直接得知当前状态是一直不可见的,仍是由可见转为不可见的 . 下面来实现这个功能 :日志
public class BaseAppearFragment extends Fragment {
private boolean isViewPrepared; // 标识fragment视图已经初始化完毕
private boolean hasAppear; //标识界面当前可见
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
//当前fragment转为可见状态
if (isVisibleToUser && isViewPrepared && !hasAppear) {
onFragmentAppear();
hasAppear = true;
}
//当前fragment转为不可见状态
if (!isVisibleToUser && hasAppear) {
onFragmentDismiss();
hasAppear = false;
}
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Log.i("zmin........." + getArguments().getInt("key"), ".............onCreateView");
return inflater.inflate(R.layout.activity_fragment, null);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
isViewPrepared = true;
TextView tv = getView().findViewById(R.id.tv);
tv.setText(String.valueOf(getArguments().getInt("key")));
Log.i("zmin........." + getArguments().getInt("key"), ".............onViewCreated");
}
@Override
public void onResume() {
super.onResume();
Log.i("zmin........." + getArguments().getInt("key"), ".............onResume(");
if (getUserVisibleHint()) {
onFragmentAppear();
hasAppear = true;
}
}
@Override
public void onDestroyView() {
isViewPrepared = true;
super.onDestroyView();
Log.i("zmin........." + getArguments().getInt("key"), ".............onDestroyView");
}
/**
* 界面可见
*/
public void onFragmentAppear() {
Log.i("zmin........." + getArguments().getInt("key"), "......界面可见..onFragmentAppear");
}
/**
* 界面由可见转为不可见
*/
public void onFragmentDismiss() {
Log.i("zmin........." + getArguments().getInt("key"), "...由可见转为不可见.........onFragmentDismiss");
}
}
复制代码
能够看到主要在在setUserVisibleHint和onResume方法中作判断. 由于Fragment切换的时候, 不少生命周期方法是不走的.
经过详细的日志 分析了Fragment生命周期的执行. 从而实现懒加载和预加载中对可见状态监听. 不少业务场景下须要用到. 若是要懒加载能够直接继承BaseLazyFragment 类便可. 若是要监听可见隐藏状态则能够继承 BaseAppearFragment . 若是还想本身去看看打印的日志. 能够clone代码, github地址 github.com/zmin666/Zmi… 但愿这些总结对你有帮助.