ViewPager與Fragment的配合使用,除了FragmentPagerAdapter之外,還有另外一個選擇FragmentStatePagerAdapter。
其實在實際應用中FragmentStatePagerAdapter相對于FragmentPagerAdapter多了兩個全局變量:
private ArrayList<Fragment.SavedState> mSavedState = new ArrayList<Fragment.SavedState>();
private ArrayList<Fragment> mFragments = new ArrayList<Fragment>();
在這個地方,需要注意的是:
①mSavedState 儲存每個Fragment的狀态資訊的清單
②mFragments 儲存每個Fragment執行個體對象的清單
接下來,貼出來源碼分析一波:
/*** 擷取給定位置對應的Fragment。
** @param position 給定的位置
* @return 對應的Fragment
* */
public abstract Fragment getItem(int position);
@Override
public void startUpdate(ViewGroup container) {}
@Override
public Object instantiateItem(ViewGroup container, int position) {
// 擷取給定位置的已存在Fragment
if (mFragments.size() > position) {
Fragment f = mFragments.get(position);
if (f != null) {
return f;
}
}
// 建立新事務
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
// 建立給定位置的Fragment
Fragment fragment = getItem(position);
if (DEBUG)
Log.v(TAG, "Adding item #" + position + ": f=" + fragment);
// 讀取給定位置的Fragment儲存的狀态,并用該狀态對Fragment進行初始化
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);
// 添加Fragment到FragmentManager中
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);
}
// 儲存目前銷毀的Fragment的狀态
mSavedState.set(position, fragment.isAdded() ? mFragmentManager.saveFragmentInstanceState(fragment) : null);
mFragments.set(position, null);
// 移除銷毀的Fragment
mCurTransaction.remove(fragment); }
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
Fragment fragment = (Fragment)object;
if (fragment != mCurrentPrimaryItem) {
// 主要項切換,相關菜單及資訊進行切換
if (mCurrentPrimaryItem != null) {
mCurrentPrimaryItem.setMenuVisibility(false);
mCurrentPrimaryItem.setUserVisibleHint(false);
}
if (fragment != null) {
fragment.setMenuVisibility(true);
fragment.setUserVisibleHint(true);
}
mCurrentPrimaryItem = fragment;
}
}
@Override
public void finishUpdate(ViewGroup container) {
if (mCurTransaction != null) {
// 送出事務
mCurTransaction.commitAllowingStateLoss();
mCurTransaction = null;
// 立即運作等待中事務
mFragmentManager.executePendingTransactions();
}
}
@Override
public boolean isViewFromObject(View view, Object object) {
return ((Fragment)object).getView() == view;
}
@Override
public Parcelable saveState() {
Bundle state = null;
if (mSavedState.size() > ) {
// 儲存Fragment狀态清單
state = new Bundle();
Fragment.SavedState[] fss = new Fragment.SavedState[mSavedState.size()];
mSavedState.toArray(fss);
state.putParcelableArray("states", fss);
}
// 儲存Fragment清單
for (int i=; i<mFragments.size(); i++) {
Fragment f = mFragments.get(i);
if (f != null && f.isAdded()) {
if (state == null) {
state = new Bundle();
}
String key = "f" + i;
mFragmentManager.putFragment(state, key, f);
}
}
return state;
}
@Override
public void restoreState(Parcelable state, ClassLoader loader) {
if (state != null) {
// 讀取Fragment狀态清單
Bundle bundle = (Bundle)state;
bundle.setClassLoader(loader);
Parcelable[] fss = bundle.getParcelableArray("states");
mSavedState.clear();
mFragments.clear();
if (fss != null) {
for (int i=; i<fss.length; i++) {
mSavedState.add((Fragment.SavedState)fss[i]);
}
}
// 讀取Fragment清單
Iterable<String> keys = bundle.keySet();
for (String key: keys) {
if (key.startsWith("f")) {
int index = Integer.parseInt(key.substring());
Fragment f = mFragmentManager.getFragment(bundle, key);
if (f != null) {
while (mFragments.size() <= index) {
mFragments.add(null);
}
f.setMenuVisibility(false);
mFragments.set(index, f);
} else {
Log.w(TAG, "Bad fragment at key " + key);
}
}
}
}
}
從源代碼中,我們可以清楚了解到FragmentStatePagerAdapter與FragmentPagerAdapter的不同:
- FragmentStatePagerAdapter對Fragment執行個體和Fragment狀态進行引用保留。
- FragmentStatePagerAdapter在instantiateItem方法中,建立新Fragment後,讀取對應Fragment狀态對其進行初始化設定,并且隻使用到add方法。
- FragmentStatePagerAdapter在destroyItem方法中,銷毀Fragment時,儲存其Fragment狀态,并且使用remove方法移除Fragment。
- FragmentStatePagerAdapter重載了saveState方法和restoreState方法,在其中對于Fragment執行個體清單和Fragment狀态清單進行儲存和讀取。
通過運作結果分析可以得到:
- 當Fragment重新被add時,Fragment的生命周期全部重新調用,但是savedInstanceState參數保留着之前存儲的資料。
- Fragment在FragmentStatePagerAdapter類的destroyItem方法中被remove時,Fragment的onDestroy方法和onDetach方法都被調用到。