转载:https://www.jb51.net/article/129574.htm
ViewPager+Fragment的搭配在日常开发中也比较常见,可用于切换展示不同类别的页面,我们日常所见的咨询、购物、金融、社交等类型的APP都有机会用到这种控件组合.
如:
ViewPager控件有个特有的预加载机制,即默认情况下当前页面左右两侧的1个页面会被加载,以方便用户滑动切换到相邻的界面时,可以更加顺畅的显示出来。预加载让用户可以更快的看到接下来的内容,浏览起来连贯性更好,但是app在展示内容的同时还增加了额外的任务,这样可能影响界面的流畅度,并且可能造成流量的浪费。
所以Fragment使用懒加载是非常有必要的。
试想那么多的分类如果一下子都加载出来,真的是极大地消耗了系统资源。可能有人会说 ViewPager 有 viewPager.setOffscreenPageLimit()
的方法,我们传个 0 进去不就好了吗?但是通过ViewPager方法setOffscreenPageLimit(int limit)
的源码可以发现,ViewPager通过一定的逻辑判断来确保至少会预加载左右两侧相邻的1个页面,也就是说无法通过简单的配置做到懒加载的效果.
ViewPager方法setOffscreenPageLimit(int limit) 相关源码:
public void setOffscreenPageLimit(int limit) { if (limit < 1) { Log.w("ViewPager", "Requested offscreen page limit " + limit + " too small; defaulting to " + 1); limit = 1; } if (limit != this.mOffscreenPageLimit) { this.mOffscreenPageLimit = limit; this.populate(); } }
如何做到懒加载?
实现思路:
使用Fragment类自带方法setUserVisibleHint()判断当前fragment是否对用户可见,根据回调的isVisibleToUser参数来进行相关的逻辑判断。重写该方法,创建变量isVisible拿到是否可见标志。
但是直接根据isVisible判断就加载数据,可能onCreateView()方法并未执行完毕,此时就会出现NullPointerException空指针异常。所以就需要满足控件初始化完成,用户可见,才能加载数据。
由于ViewPager内会装载多个Fragment,而这种懒加载机制对于各个Fragment属于共同操作,因此适合将其抽取到BaseFragment中.
注意:
setUserVisibleHint(boolean isVisibleToUser)
方法会多次回调,而且可能会在onCreateView()
方法执行完毕之前回调.如果isVisibleToUser==true,然后进行数据加载和控件数据填充,但是onCreateView()
方法并未执行完毕,此时就会出现NullPointerException空指针异常.
基于以上原因,我们进行数据懒加载的时机需要满足两个条件
onCreateView()
方法执行完毕setUserVisibleHint(boolean isVisibleToUser)
方法返回true
所以在BaseFragment中用两个布尔型标记来记录这两个条件的状态.只有同时满足了,才能加载数据
LazyloadFragment 代码:
public abstract class LazyloadFragment extends Fragment { protected View rootView; private boolean isInitView = false; private boolean isVisible = false; @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { rootView = inflater.inflate(setContentView(), container, false); init(); isInitView = true; isCanLoadData(); return rootView; } @Override public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); //isVisibleToUser这个boolean值表示:该Fragment的UI 用户是否可见,获取该标志记录下来 if (isVisibleToUser) { isVisible = true; isCanLoadData(); } else { isVisible = false; } } private void isCanLoadData() { //所以条件是view初始化完成并且对用户可见 if (isInitView && isVisible) { lazyLoad(); //防止重复加载数据 isInitView = false; isVisible = false; } } }
Fragment 代码:
public class PageFragment extends LazyloadFragment implements XRecyclerView.LoadingListener { private CommonAdapter<String> adapter; private ArrayList<String> datas = new ArrayList<>(); private XRecyclerView recyclerView; private Handler handler = new Handler(); @Override public int setContentView() { return R.layout.fragment_page; } @Override public void init() { recyclerView = rootView.findViewById(R.id.recyclerview); recyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); adapter = new CommonAdapter<String>(getActivity(),R.layout.item,datas) { @Override protected void convert(ViewHolder holder, String s, int position) { } }; recyclerView.setAdapter(adapter); recyclerView.setPullRefreshEnabled(true); recyclerView.setLoadingListener(this); } @Override public void lazyLoad() { recyclerView.refresh(); } @Override public void onRefresh() { handler.postDelayed(new Runnable() { @Override public void run() { recyclerView.refreshComplete(); for(int i=0;i<10;i++){ datas.add(""); } adapter.notifyDataSetChanged(); } },500); } @Override public void onLoadMore() { } }
MainActivity 代码:
public class MainActivity extends AppCompatActivity { private TabLayout tabLayout; private String[] topics = new String[]{"推荐","热点","北京","视频","社会","图片"}; private ViewPager viewPager; private ArrayList<Fragment> fragments = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); setContentView(R.layout.activity_main); init(); } private void init() { viewPager = (ViewPager) findViewById(R.id.viewpager); tabLayout = (TabLayout) findViewById(R.id.tablayout); viewPager.setOffscreenPageLimit(3); for(int i=0;i<topics.length;i++){ tabLayout.addTab(tabLayout.newTab()); fragments.add(new PageFragment()); } viewPager.setAdapter(new FmPagerAdapter(fragments,getSupportFragmentManager())); tabLayout.setupWithViewPager(viewPager); for (int j = 0; j < topics.length; j++) { tabLayout.getTabAt(j).setText(topics[j]); } } }
大坑:
大家千篇一律地说用setUserVisibleHint()方法就可以了,但是没有说这个问题。是不是用了Lazyloadfragment不加载数据了?因为你用的是Viewpager用的是PagerAdapter,用pageradapter,打断点调试,根本就没有调用setUserVisibleHint(),所以isVisible还是false,不执行lazyload方法。需要用FragmentPagerAdapter显示调用setUserVisibleHint()。