FragmentPagerAdapter 和 FragmentStatePagerAdapter 内部都封裝有 FragmentManager和 FragmentTransaction,用于管理Fragment;
使用Fragment 來表示一頁,顯得更加簡單和直覺,Fragment 本身提供的一些特性可以讓我們友善的對每一頁進行管理,使用FragmentManager可以根據ID或TAG來查找Fragment , 動态添加、删除、替換,Fragment 可以管理自己的生命周期,像Activity一樣提供了一些生命周期回調方法
讓Fragment 成為ViewPager的一頁時,FragmentManager會一直儲存管理建立好了的Fragment,即使目前不是顯示的這一頁,Fragment對象也不會被銷毀,在背景默默等待重新顯示。但如果Fragment不再可見時,它的視圖層次會被銷毀掉,下次顯示時視圖會重新建立
首先來分析一下 FragmentPagerAdapter:
@Override
public Object instantiateItem(ViewGroup container, int position) {
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
final long itemId = getItemId(position);
// Do we already have this fragment?
String name = makeFragmentName(container.getId(), itemId);
Fragment fragment = mFragmentManager.findFragmentByTag(name);
if (fragment != null) {
if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);
mCurTransaction.attach(fragment);
} else {
fragment = getItem(position);
mCurTransaction.add(container.getId(), fragment,
makeFragmentName(container.getId(), itemId));
}
return fragment;
}
在FragmentPagerAdapter 裡的instantiateItem方法執行個體化Fragment,首先通過TAG去找Fragment是否存在,如果不存在調用getItem()添加,子類需要複寫getItem()
public void destroyItem(ViewGroup container, int position, Object object) {
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
if (DEBUG) Log.v(TAG, "Detaching item #" + getItemId(position) + ": f=" + object
+ " v=" + ((Fragment)object).getView());
mCurTransaction.detach((Fragment)object);
}
在destroyItem()方法中僅僅是把Fragment detach掉,Fragment界面被銷毀,但是Fragment還在記憶體中沒有銷毀
是以在使用FragmentPagerAdapter 時,Fragment對象會一直存留在記憶體中,是以當有大量的顯示頁時,就不适合用FragmentPagerAdapter 了,FragmentPagerAdapter 适用于隻有少數的page情況,像頁籤
接下來看FragmentStatePagerAdapter 源碼:
@Override
public Object instantiateItem(ViewGroup container, int position) {
// If we already have this item instantiated, there is nothing
// to do. This can happen when we are restoring the entire pager
// from its saved state, where the fragment manager has already
// taken care of restoring the fragments we previously had instantiated.
if (mFragments.size() > position) {
Fragment f = mFragments.get(position);
if (f != null) {
return f;
}
}
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
Fragment fragment = getItem(position);
if (mSavedState.size() > position) {
Fragment.SavedState fss = mSavedState.get(position);
if (fss != null) {
fragment.setInitialSavedState(fss);
}
}
while (mFragments.size() <= position) {
mFragments.add(null);
}
fragment.setMenuVisibility(false);
fragment.setUserVisibleHint(false);
mFragments.set(position, fragment);
mCurTransaction.add(container.getId(), fragment);
return fragment;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
Fragment fragment = (Fragment) object;
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
if (DEBUG) Log.v(TAG, "Removing item #" + position + ": f=" + object
+ " v=" + ((Fragment)object).getView());
while (mSavedState.size() <= position) {
mSavedState.add(null);
}
mSavedState.set(position, fragment.isAdded()
? mFragmentManager.saveFragmentInstanceState(fragment) : null);
mFragments.set(position, null);
mCurTransaction.remove(fragment);
}
從源碼上看當使用 FragmentStatePagerAdapter 時,如果Fragment不顯示,那麼Fragment對象會被銷毀,但在回調onDestroy()方法之前會回調onSaveInstanceState(Bundle outState)方法來儲存Fragment的狀态,下次Fragment顯示時通過onCreate(Bundle savedInstanceState)把存儲的狀态值取出來, FragmentStatePagerAdapter 比較适合頁面比較多的情況,像一個頁面的ListView item