1. ViewPager源码分析
1>:点击 viewPager.setAdapter进入下边源码,会调用 populate() 方法,这个方法作用是创建和销毁子条目(子item):
/**
* Set a PagerAdapter that will supply views for this pager as needed.
*
* @param adapter Adapter to use
*/
public void setAdapter(PagerAdapter adapter) {
populate();
}
void populate(int newCurrentItem) {
if (curItem == null && N > 0) {
// 创建item
curItem = addNewItem(mCurItem, curIndex);
}
if (pos == ii.position && !ii.scrolling) {
// 销毁item
mAdapter.destroyItem(this, pos, ii.object);
}
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();
}
}
在populate()方法中:
创建ItemView:mAdapter.instantiateItem(this, position);
销毁ItemView:mAdapter.destroyItem(this, pos, ii.object);
所以由ViewPager的源码可以看出,ViewPager里边无论放多少个页面都不会内存溢出,它会不断的去创建和销毁view;
和 ListView、RecyclerView不一样,ListView、RecyclerView是会不断的复用view,而viewpager是不断的创建和销毁view
2. ViewPager加载页面的原理如图所示:
轮播图刚打开默认显示当前页,是第一页,默认会缓存左右两个页面,如果左边没有,只有右边有,那么右边是第0页,当前页是第一页;
如果你滑动到第1页,ViewPager会默认把 左边第0页 和 右边第2页 创建出来;
如果你滑动到第2页,ViewPager会默认把第1页和第3页创建出来,而原来的第0页就会变成需要销毁的页面;
如果想要缓存多页,可以调用setOffscreenPageLimit()方法:
setOffscreenPageLimit(1):ViewPager机制默认就是缓存1,表示左边、右边各缓存1页,加上自己,总共是3页,其余页面全部销毁;
setOffscreenPageLimit(2):表示默认给左右各缓存2页,共4页,加上自己,总共缓存5页,其余页面全部销毁;
setOffscreenPageLimit(3):表示默认给左右各缓存3页,共6页,加上自己,总共缓存7页,其余页面全部销毁;
3. 总结:
1>:ViewPager真正的子View只是两边 "缓存" 的页面+1(当前显示页面),那么ViewPager如何做到从头滑动到尾不出问题呢?
因为 smoothScrollTo()滑动方法也调用populate(),而populate()方法维护了当前显示页面和 左右缓存的页面,就能做到无限滑动而不出问题;
2>:populate()如何让 ViewPager的子View 一直保持为 两边"缓存"页面 + 当前页面?
A:从populate()源码中可知:先判断页面是否在缓存范围内:如果在,则addNewItem添加进来,否则在destroyItem掉;
B:ViewPager会缓存左右两边页面+1(当前显示页面),默认认为当前页面的 左右两边各有1个,用户可以手动调用setOffscreenPageLimit()方法设置数量,如果传的值小于1,就默认设置为1;
ViewPager实际示意图如下: