安卓開(kāi)發(fā)之FragmentPagerAdapter和FragmentStatePagerAdapter詳解
最近遇到比較奇怪的bug,TableLayout+ViewPager實(shí)現(xiàn)點(diǎn)擊頂部tab切換viewpager視圖。但是在Viewpager設(shè)置dapter時(shí),最開(kāi)始設(shè)置的是FragmentPagerAdapter,會(huì)導(dǎo)致tab切換后FragmentPagerAdapter內(nèi)的視圖未刷新(與上一個(gè)tab內(nèi)容重復(fù)或展示成空白,展示成空白一般出現(xiàn)在頁(yè)面重啟后不能完成刷新成功)。替換成FragmentStatePagerAdapter或者FragmentStateAdapter,便解決了這一問(wèn)題。這其實(shí)是個(gè)比較常見(jiàn)的bug,網(wǎng)絡(luò)上有很多推薦的解決方案。那么到底FragmentPagerAdapter、FragmentStateAdapter以及FragmentStatePagerAdapter有何具體的區(qū)別呢?在這篇文章中我將詳細(xì)解答。
根據(jù)類圖進(jìn)行分析
FragmentPagerAdapter與FragmentPagerStateAdapter區(qū)別點(diǎn):
一:二者在狀態(tài)保存有差異:FragmentPagerAdapter并未實(shí)現(xiàn)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則實(shí)現(xiàn)了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對(duì)Fragment的狀態(tài)進(jìn)行了保存
二:二者在視圖管理方法差異:
FragmentStatePagerAdapter是整個(gè)Fragment對(duì)象的移除和重建
?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();
? ? ? ? }
?
? ? ? ? // 實(shí)例化fragment(交給我們實(shí)現(xiàn)的getItem方法)
? ? ? ? Fragment fragment = getItem(position);
?
? ? ? ? if (mSavedState.size() > position) {
? ? ? ? ? ? Fragment.SavedState fss = mSavedState.get(position);
? ? ? ? ? ? if (fss != null) {
? ? ? ? ? ? ? ? fragment.setInitialSavedState(fss);
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? // 如果緩存 <= ViewPager傳入的position,說(shuō)明當(dāng)前位置還未存入緩存.
? ? ? ? while (mFragments.size() <= position) {
? ? ? ? ? ? // 先占個(gè)坑
? ? ? ? ? ? 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,不會(huì)對(duì)整個(gè)fragment進(jìn)行完全的添加和刪除操作。
因此,可見(jiàn)二者在使用場(chǎng)景上不同,如果頁(yè)面較少,仍舊希望能夠?qū)⑸傻腇ragment保存在內(nèi)存中,在需要顯示的時(shí)候直接調(diào)用。而不要產(chǎn)生生成、銷毀對(duì)象的額外開(kāi)銷。這樣效率最高。這種情況下,選中FragmentPagerAdapter更合適。
對(duì)于在使用FragmentPagerAdapter出現(xiàn)白屏或者刷新不了的bug,除了替換成FragmentStatePagerAdapter,還需要重載getItem()和instantiateItem()對(duì)象。
對(duì)于getItemPosition()方法,兩個(gè)累的區(qū)別是:FragmentStatePagerAdapter會(huì)在因POSITION_NONE觸發(fā)調(diào)用的destroyItem中真正的釋放資源,重新建立一個(gè)新的Fragment;而FragmentPagerAdapter僅僅會(huì)在destoryItem()中detach這個(gè)Fragment,在instantiateItem()時(shí)會(huì)使用舊的Fragment,并觸發(fā)attach,并沒(méi)有觸發(fā)資源及重建的過(guò)程。
到此這篇關(guān)于安卓開(kāi)發(fā)之FragmentPagerAdapter和FragmentStatePagerAdapter詳解的文章就介紹到這了,更多相關(guān)FragmentPagerAdapter和FragmentStatePagerAdapter詳解內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Android基礎(chǔ)之使用Fragment控制切換多個(gè)頁(yè)面
- Android基礎(chǔ)之Fragment與Activity交互詳解
- Android中fragment嵌套fragment問(wèn)題解決方法
- Android程序開(kāi)發(fā)之Fragment實(shí)現(xiàn)底部導(dǎo)航欄實(shí)例代碼
- Android的Fragment的生命周期各狀態(tài)和回調(diào)函數(shù)使用
- Android Fragment 基本了解(圖文介紹)
- Android fragment實(shí)現(xiàn)多個(gè)頁(yè)面切換效果
- Android 管理Activity中的fragments
- Fragment里添加ListView不要用ListFragment
- FrameLayout和Fragment處理Android應(yīng)用UI布局實(shí)例
相關(guān)文章
Activity跳轉(zhuǎn)時(shí)生命周期跟蹤的實(shí)例
下面小編就為大家?guī)?lái)一篇Activity跳轉(zhuǎn)時(shí)生命周期跟蹤的實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-03-03
Android實(shí)現(xiàn)動(dòng)態(tài)向Gallery中添加圖片及倒影與3D效果示例
這篇文章主要介紹了Android實(shí)現(xiàn)動(dòng)態(tài)向Gallery中添加圖片及倒影與3D效果的方法,涉及Android針對(duì)圖片的加載、顯示、翻轉(zhuǎn)、倒影等相關(guān)特效功能實(shí)現(xiàn)技巧2016-08-08
Android自定義View實(shí)現(xiàn)豎直跑馬燈效果案例解析
這篇文章主要為大家詳細(xì)介紹了Android自定義View實(shí)現(xiàn)豎直跑馬燈效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-07-07
Kotlin實(shí)現(xiàn)半圓形進(jìn)度條的方法示例
這篇文章主要給大家介紹了關(guān)于Kotlin實(shí)現(xiàn)半圓形進(jìn)度條的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2018-03-03
gradle tool升級(jí)到3.0注意事項(xiàng)小結(jié)
這篇文章主要介紹了gradle tool升級(jí)到3.0注意事項(xiàng)及修改相關(guān)文件介紹,需要的朋友可以參考下2018-02-02
android為L(zhǎng)istView每個(gè)Item上面的按鈕添加事件
本篇文章主要介紹了android為L(zhǎng)istView每個(gè)Item上面的按鈕添加事件,有興趣的同學(xué)可以了解一下。2016-11-11
Android 自定義組件成JAR包的實(shí)現(xiàn)方法
這篇文章主要介紹了Android 自定義組件成JAR包的實(shí)現(xiàn)方法的相關(guān)資料,偶爾會(huì)用到這樣的功能,如果你自己自定義的組件很好,需要的朋友可以參考下2016-11-11
深入理解Android熱修復(fù)技術(shù)原理之代碼熱修復(fù)技術(shù)
在各種 Android 熱修復(fù)方案中,Andfix的即時(shí)生效令人印象深刻,它稍顯另類, 并不需要重新啟動(dòng),而是在加載補(bǔ)丁后直接對(duì)方法進(jìn)行替換就可以完成修復(fù),然而它的使用限制也遭遇到更多的質(zhì)疑2021-06-06
Android?動(dòng)態(tài)加載?so實(shí)現(xiàn)示例詳解
這篇文章主要為大家介紹了Android?動(dòng)態(tài)加載?so實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09
Android getJSONObject與optJSONObject的區(qū)別結(jié)合源碼分析
這篇文章主要介紹了Android getJSONObject與optJSONObject的區(qū)別,結(jié)合源碼分析的相關(guān)資料,需要的朋友可以參考下2017-02-02

