安卓開發之FragmentPagerAdapter和FragmentStatePagerAdapter詳解
最近遇到比較奇怪的bug,TableLayout+ViewPager實現點擊頂部tab切換viewpager視圖。但是在Viewpager設置dapter時,最開始設置的是FragmentPagerAdapter,會導致tab切換後FragmentPagerAdapter內的視圖未刷新(與上一個tab內容重復或展示成空白,展示成空白一般出現在頁面重啟後不能完成刷新成功)。替換成FragmentStatePagerAdapter或者FragmentStateAdapter,便解決瞭這一問題。這其實是個比較常見的bug,網絡上有很多推薦的解決方案。那麼到底FragmentPagerAdapter、FragmentStateAdapter以及FragmentStatePagerAdapter有何具體的區別呢?在這篇文章中我將詳細解答。
根據類圖進行分析
FragmentPagerAdapter與FragmentPagerStateAdapter區別點:
一:二者在狀態保存有差異:FragmentPagerAdapter並未實現saveState()、restoreState()
public class FragmentPagerAdapter{ // ...... public static final int POSITION_UNCHANGED = -1; public static final int POSITION_NONE = -2; public Parcelable saveState() { return null; } public void restoreState(Parcelable state, ClassLoader loader) { } }
而FragmentPagerStateAdapter則實現瞭saveState()、restoreState()這倆方法:
public Parcelable saveState() { Bundle state = null; if (mSavedState.size() > 0) { state = new Bundle(); Fragment.SavedState[] fss = new Fragment.SavedState[mSavedState.size()]; mSavedState.toArray(fss); state.putParcelableArray("states", fss); } for (int i=0; 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) { Bundle bundle = (Bundle)state; bundle.setClassLoader(loader); Parcelable[] fss = bundle.getParcelableArray("states"); mSavedState.clear(); mFragments.clear(); if (fss != null) { for (int i=0; i<fss.length; i++) { mSavedState.add((Fragment.SavedState)fss[i]); } } Iterable<String> keys = bundle.keySet(); for (String key: keys) { if (key.startsWith("f")) { int index = Integer.parseInt(key.substring(1)); 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對Fragment的狀態進行瞭保存
二:二者在視圖管理方法差異:
FragmentStatePagerAdapter是整個Fragment對象的移除和重建
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(交給我們實現的getItem方法) Fragment fragment = getItem(position); if (mSavedState.size() > position) { Fragment.SavedState fss = mSavedState.get(position); if (fss != null) { fragment.setInitialSavedState(fss); } } // 如果緩存 <= ViewPager傳入的position,說明當前位置還未存入緩存. while (mFragments.size() <= position) { // 先占個坑 mFragments.add(null); } 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(); } // 從緩存中移除 mFragments.set(position, null); // 從FragmentManager中移除 mCurTransaction.remove(fragment); }
FragmentPagerAdapter是視圖的attach和detach,不會對整個fragment進行完全的添加和刪除操作。
因此,可見二者在使用場景上不同,如果頁面較少,仍舊希望能夠將生成的Fragment保存在內存中,在需要顯示的時候直接調用。而不要產生生成、銷毀對象的額外開銷。這樣效率最高。這種情況下,選中FragmentPagerAdapter更合適。
對於在使用FragmentPagerAdapter出現白屏或者刷新不瞭的bug,除瞭替換成FragmentStatePagerAdapter,還需要重載getItem()和instantiateItem()對象。
對於getItemPosition()方法,兩個累的區別是:FragmentStatePagerAdapter會在因POSITION_NONE觸發調用的destroyItem中真正的釋放資源,重新建立一個新的Fragment;而FragmentPagerAdapter僅僅會在destoryItem()中detach這個Fragment,在instantiateItem()時會使用舊的Fragment,並觸發attach,並沒有觸發資源及重建的過程。
到此這篇關於安卓開發之FragmentPagerAdapter和FragmentStatePagerAdapter詳解的文章就介紹到這瞭,更多相關FragmentPagerAdapter和FragmentStatePagerAdapter詳解內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- 設置界面開發Preference Library數據重建機制詳解
- Android性能優化之ViewPagers + Fragment緩存優化
- ViewPager+Fragment實現側滑導航欄
- Android開發之Fragment懶加載的幾種方式及性能對比
- Kotlin四大組件中的broadcast廣播