1. ViewPager源碼分析
1>:點(diǎn)擊 viewPager.setAdapter進(jìn)入下邊源碼,會(huì)調(diào)用 populate() 方法,這個(gè)方法作用是創(chuàng)建和銷毀子條目(子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) {
// 創(chuàng)建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()方法中:
創(chuàng)建ItemView:mAdapter.instantiateItem(this, position);
銷毀ItemView:mAdapter.destroyItem(this, pos, ii.object);
所以由ViewPager的源碼可以看出,ViewPager里邊無(wú)論放多少個(gè)頁(yè)面都不會(huì)內(nèi)存溢出,它會(huì)不斷的去創(chuàng)建和銷毀view;
和 ListView、RecyclerView不一樣,ListView、RecyclerView是會(huì)不斷的復(fù)用view,而viewpager是不斷的創(chuàng)建和銷毀view
2. ViewPager加載頁(yè)面的原理如圖所示:

輪播圖剛打開默認(rèn)顯示當(dāng)前頁(yè),是第一頁(yè),默認(rèn)會(huì)緩存左右兩個(gè)頁(yè)面,如果左邊沒(méi)有,只有右邊有,那么右邊是第0頁(yè),當(dāng)前頁(yè)是第一頁(yè);
如果你滑動(dòng)到第1頁(yè),ViewPager會(huì)默認(rèn)把 左邊第0頁(yè) 和 右邊第2頁(yè) 創(chuàng)建出來(lái);
如果你滑動(dòng)到第2頁(yè),ViewPager會(huì)默認(rèn)把第1頁(yè)和第3頁(yè)創(chuàng)建出來(lái),而原來(lái)的第0頁(yè)就會(huì)變成需要銷毀的頁(yè)面;
如果想要緩存多頁(yè),可以調(diào)用setOffscreenPageLimit()方法:
setOffscreenPageLimit(1):ViewPager機(jī)制默認(rèn)就是緩存1,表示左邊、右邊各緩存1頁(yè),加上自己,總共是3頁(yè),其余頁(yè)面全部銷毀;
setOffscreenPageLimit(2):表示默認(rèn)給左右各緩存2頁(yè),共4頁(yè),加上自己,總共緩存5頁(yè),其余頁(yè)面全部銷毀;
setOffscreenPageLimit(3):表示默認(rèn)給左右各緩存3頁(yè),共6頁(yè),加上自己,總共緩存7頁(yè),其余頁(yè)面全部銷毀;
3. 總結(jié):
1>:ViewPager真正的子View只是兩邊 "緩存" 的頁(yè)面+1(當(dāng)前顯示頁(yè)面),那么ViewPager如何做到從頭滑動(dòng)到尾不出問(wèn)題呢?
因?yàn)?smoothScrollTo()滑動(dòng)方法也調(diào)用populate(),而populate()方法維護(hù)了當(dāng)前顯示頁(yè)面和 左右緩存的頁(yè)面,就能做到無(wú)限滑動(dòng)而不出問(wèn)題;
2>:populate()如何讓 ViewPager的子View 一直保持為 兩邊"緩存"頁(yè)面 + 當(dāng)前頁(yè)面?
A:從populate()源碼中可知:先判斷頁(yè)面是否在緩存范圍內(nèi):如果在,則addNewItem添加進(jìn)來(lái),否則在destroyItem掉;
B:ViewPager會(huì)緩存左右兩邊頁(yè)面+1(當(dāng)前顯示頁(yè)面),默認(rèn)認(rèn)為當(dāng)前頁(yè)面的 左右兩邊各有1個(gè),用戶可以手動(dòng)調(diào)用setOffscreenPageLimit()方法設(shè)置數(shù)量,如果傳的值小于1,就默認(rèn)設(shè)置為1;
ViewPager實(shí)際示意圖如下:
