FragmentPagerAdapter和FragmentStatePagerAdapter的區(qū)別
FragmentPagerAdapter和FragmentStatePagerAdapter在Android開發(fā)中都是用于給ViewPager進行數(shù)據(jù)適配的適配器,在使用和管理Fragment的方式上兩者存在顯著的區(qū)別。
FragmentPagerAdapter在切換Fragment時,不會銷毀Fragment,而只是調(diào)用事務中的detach方法。因此Fragment的視圖(view)會被銷毀,而Fragment的實例會保留在FragmentManager中。通過這種方式創(chuàng)建的Fragment一直不會被銷毀,適用于一些靜態(tài)的Fragment,例如一組tabs。這也可能導致在Fragment數(shù)量較大時,應用程序占用過多資源。
FragmentStatePagerAdapter在切換不同的Fragment時,會銷毀不再需要的Fragment。在銷毀Fragment前,會先將Fragment的狀態(tài)信息(通過onSaveInstanceState(Bundle)方法保存)保存在Bundle中。切換回原來的頁面后,保存的狀態(tài)可用于恢復生成新的Fragment。適用于頁面數(shù)量較大或需要動態(tài)加載和銷毀Fragment的場景,能有效地管理內(nèi)存使用。
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);
if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment);
mCurTransaction.add(container.getId(), fragment,
makeFragmentName(container.getId(), itemId));
}
if (fragment != mCurrentPrimaryItem) {
fragment.setMenuVisibility(false);
fragment.setUserVisibleHint(false);
}
return fragment;
}
在instantiateItem方法中,主要是將Fragment添加到FragmentManager中。未添加到FragmentManager中的執(zhí)行add操作,已添加到FragmentManager中的只進行attach操作。
@Override
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方法中,只是進行detach操作。detach操作并不會將Fragment銷毀,F(xiàn)ragment依舊是由FragmentManager進行管理。
FragmentStatePagerAdapter源碼
@Override
public Object instantiateItem(ViewGroup container, int position) {
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 (DEBUG) Log.v(TAG, "Adding item #" + position + ": f=" + 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);
mCurTransaction.add(container.getId(), fragment);
return fragment;
}
FragmentStatePagerAdapter是通過一個mFragments數(shù)組來存儲Fragment的,通過mSavedState數(shù)組來存儲Fragment銷毀時的狀態(tài),通過position獲取到的Fragment可能為空(被回收),如果為空,則會再次調(diào)用getItem方法重新創(chuàng)建新的Fragment,然后將mSavedState中存儲的狀態(tài)重新賦予這個新的Fragment, 達到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);
}
當item在頁面中不可見時,該Fragment的狀態(tài)會先被保存到mSavedState中,而Fragment實例則會被銷毀。
總結(jié)
FragmentPagerAdapter和FragmentStatePagerAdapter在Android開發(fā)中都是用于與ViewPager配合使用的適配器。
相同點:
- 繼承自PagerAdapter:都繼承自PagerAdapter,基本功能和用法一樣。
- 管理Fragment:都是用來管理Fragment的適配器,使ViewPager能夠展示一系列的Fragment。
- 保持當前和前后Fragment狀態(tài):在顯示當前Fragment的同時,Adapter會提前初始化后一個Fragment,并把當前Fragment的前一個Fragment保存在內(nèi)存中。
不同點:
(1) Fragment銷毀策略:
- FragmentPagerAdapter:不會銷毀已經(jīng)創(chuàng)建的Fragment實例,而是保存在內(nèi)存中。當Fragment不再可見時,只會調(diào)用detach方法,銷毀Fragment的視圖(View),保留Fragment的實例。切換回之前的Fragment,可以快速重新綁定視圖,而不需要重新創(chuàng)建Fragment實例。這種方式適用于Fragment數(shù)量較少,且不需要頻繁創(chuàng)建和銷毀的場景。
- FragmentStatePagerAdapter:在不再需要某個Fragment時完全銷毀。當Fragment滑出屏幕范圍后,實例和視圖都會被銷毀。切換回該Fragment時,會重新創(chuàng)建Fragment實例和視圖。這種方式適用于Fragment數(shù)量較多,或者需要動態(tài)加載和銷毀Fragment的場景,以避免占用過多內(nèi)存。
(2) 狀態(tài)保存與恢復:
- FragmentStatePagerAdapter:在銷毀Fragment之前,會在onSaveInstanceState(Bundle)方法中保存Fragment的狀態(tài)信息。切換回原來的Fragment時,可以使用這些保存的狀態(tài)信息來恢復Fragment的狀態(tài)。
- FragmentPagerAdapter:由于不會銷毀Fragment實例,不需要在銷毀前保存狀態(tài),也不需要在恢復時重新加載狀態(tài)。
FragmentPagerAdapter和FragmentStatePagerAdapter的主要區(qū)別在于它們對Fragment生命周期的管理方式。前者保留Fragment實例,適用于Fragment數(shù)量較少且不需要頻繁創(chuàng)建和銷毀的場景;后者在不再需要時銷毀Fragment,適用于Fragment數(shù)量較多或需要動態(tài)加載和銷毀的場景。