android fragmentstatepageradapter框架,安卓爬坑指南之FragmentStatePagerAdapter
一次開發中,用到了viewpager嵌套viewpager,結果就踩到了這么一個坑。
先上圖:
image.png
圖片中顯示的界面布局和遇到的問題是這樣的:首頁發現版塊是一個fragment,這個fragment中放了一個viewpager,這個viewpager有三頁,其中最后一頁對應的fragment又放了一個viewpager,內層的viewpager有兩頁。進入發現時,從外層viewpager第一頁切到第三頁,加載內層viewpager第一頁的數據,然后切回外層viewpager第一頁,當再次切到外層viewpager第三頁時,出現了神奇的一幕,之前加載的內層viewpager第一頁界面展示的數據神奇的不見了。
好吧,我自己都被說暈了,反正大概就是這么一個情況。
首先我外層viewpager和內層viewpager用的adapter都是繼承自FragmentStatePagerAdapter,viewpager的默認緩存頁為1,因此首先我可以確認的是,外層viewpager在第一頁和第三頁切換顯示時,fragment會有銷毀和創建。當外層viewpager從第三頁切回第一頁時,此時第三頁的fragment被釋放,正常的邏輯是第三頁fragment內層的viewpager包含的兩個fragment也是被釋放的,當然,這也只是理論上的。為了驗證自己的猜想,我在對應fragment onDestory方法中寫一條Log,下面是控制臺輸出的截圖:
logcat.png
Log的顯示驗證了我的猜想,所以問題到底出在哪里呢?我們繼續寫Log,這次我們把外層viewpager第三頁的fragment和內層viewpager第一頁fragment內存地址輸出來:
first.png
second.png
比較來回切換兩次的控制臺信息我們可以看到,外層viewpager第三頁的fragment內存地址沒有變化,因為viewpager數據源沒有變,fragment只是重走了生命周期,而fragment重新走生命周期時,內層viewpager對應的數據源是重新創建的,控制臺打印的內層viewpager第一頁fragment內存地址不一樣正好驗證了這是兩個fragment,既然兩個對象都不一樣,fragment重新創建,數據重新加載,就不存在界面數據不顯示的問題,可是結果并不是我想的那樣,這就尷尬了!
冷靜的思考了一下,既然fragment是重新創建的,會不會出現adapter返回的fragment不一致呢?繼續寫Log:
first1.png
second1.png
看完Log我驚呆了,第二次重新創建了fragment,但是adapter竟然沒有返回fragment,wtf???那adapter沒有返回fragment,界面顯示的fragment哪里來的呢?第一反應想的是不是適配器有緩存,切回來時直接走的緩存,查閱FragmentStatePagerAdapter源碼,果不其然,被我找到了!源碼如下:
@Override
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
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
mSavedState.add((Fragment.SavedState)fss[i]);
}
}
Iterable 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的數據源不為空,viewpager在被銷毀時,FragmentStatePagerAdapter會自動保存數據;我們接著寫Log看看這兩個方法到底有沒有走:
first2.png
second2.png
果然,FragmentStatePagerAdapter在外層viewpager第三頁fragment銷毀時保存了狀態,再次切回來時,雖然fragment重走了生命周期,但是由于FragmentStatePagerAdapterde直接取的緩存,銷毀時只保存了fragment的狀態,切回時緩存的fragment狀態恢復,但是數據源已經釋放,從而導致界面數據不顯示。
至此,我們終于找到了bug罪魁禍首!所以這個問題的解決方案是去掉FragmentStatePagerAdapterde 緩存,具體代碼如下:
public class BaseFragmentPageAdapter extends FragmentStatePagerAdapter {
public BaseFragmentPageAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
return null;
}
@Override
public int getCount() {
return 0;
}
@Override
public Parcelable saveState() {
return null;
}
@Override
public void restoreState(Parcelable state, ClassLoader loader) {
}
}
講了這么多,不知道各位有沒有看懂!😂😂😂
如果大家有遇到類似的問題,希望這篇博客對你們有幫助,最后,希望大家多多鼓勵,我會繼續努力把博客寫的更好!
總結
以上是生活随笔為你收集整理的android fragmentstatepageradapter框架,安卓爬坑指南之FragmentStatePagerAdapter的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 新三板申购新股的条件
- 下一篇: 微信微粒贷怎么开通,在哪里能找到