引言
ViewPager + Fragment + TabLayout的模式已经很常见了,例如今日头条等等,如果今日头条是ViewPager + Fragment + TabLayout的实现方式,那表现形式上就是一个ViewPager管理多个Fragment,左右滑动来回切换。而ViewPager有一特性(预加载),比如打开应用,先看到的是Tab1(推荐),但这时候Tab2(热点)已经加载好了。当切换到Tab2(热点),Tab3(所在的城市)已经加载好了(前提是没有自己处理)。
但是上面所说ViewPager + Fragment + TabLayout的这种组合并不是通用的,因为有时候用户希望选择了哪个Tab再去加载哪个Tab的数据,而不是预加载,如果当前页面和预加载页面都有大量的网络请求,可能就会比较慢。(但是如果数据量较少的话切换能更顺畅,根据自己的需求去选择吧)关于这个问题,众说纷纭,比如弃用ViewPager,或者直接禁掉ViewPager预加载。
其实那些说通过调用ViewPager的setOffscreenPageLimit(int limit),来设置ViewPager预加载的数量,来达到禁止预加载。这是不行的,因为ViewPager中的这个默认值为1,具体源码如下:
private static final int DEFAULT_OFFSCREEN_PAGES = 1;
...此处省略
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();
}
}
根据查看源码,ViewPager中DEFAULT_OFFSCREEN_PAGES 默认值为1,即默认会预加载当前页面左右各一个页面,如果你设置的值小于默认值,它依然设置的是1。
看到这里你是不是想说:“既然它的默认值1,那是不是可以自己写一个ViewPager,代码一样,只是把默认值修改为0?”其实理论上是可以的,但是…目前Android的API已经更新到27了,而且每个版本v4包是有差异的。所以如果要实现选择了哪个Tab再去加载哪个Tab的数据,可以使用下文方案。
加载方案
依靠Fragment的setUserVisibleHint(boolean isVisibleToUser)
的方法,我们可以在这个方法里做判断,当其true时(当前fragment视图用户可见)时再去加载数据。
而setUserVisibleHint(boolean isVisibleToUser)
方法会在界面可见和不可见都会调用,而且fragment首次加载时此方法会在onCreateView
之前调用,所以直接在此方法中去加载数据,可能会导致空指针异常,所以得确保视图初始化以后(isInit = true),再去加载数据。如下:
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.activity_all_order, container, false);
init(view);
return view;
}
private void init(View view) {
isInit = true;
presenter = new PayOrderPresenter();
presenter.setView(this);
emptyView = view.findViewById(R.id.empty_layout);
recyclerView = (PtrDefRecyclerView) view.findViewById(R.id.recycler_view);
LinearLayoutManager manager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(manager);
recyclerView.setOnLoadListener(this);
recyclerView.setOnRefreshListener(this);
mAdapter = new AllOrderAdapter();
recyclerView.setAdapter(mAdapter);
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
if (isInit) {
//加载数据
loadData();
}
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
isInit = false;
}
这样就能够保证加载数据的时候不会出现空指针异常,而且每次切换到当前fragment的时候都会去加载数据,也达到了利用ViewPager的预加载来初始化视图。
PS:以上仅仅是自己在开发中实现的方案,如果各位大佬有更好或者更简单的方案,欢迎分享学习。