如果出現fragment中onSavedInstanceState中保存的狀態在fragment再次創建的時候無法獲取,那么這篇文章正是你想要的。
我們很多應用都是由下面n個tab,上面n個fragment組合成的。
很多應用在MainActivity里的onCreate里去 一 一 實例化fragment,然后在tab切換的時候使用FragmentTransaction去添加或者替換fragment。
大概是這么寫的
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.e("StateActivity", "---------------onCreate");
setContentView(R.layout.activity_main_for_state);
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.state_fragment_container, Fragment1.newInstance("", ""));
ft.commit();
}
這種有沒有問題呢?看著好像沒有問題,但是如果你的fragment里需要保存狀態那就有問題了。
我們有A,B兩個Activity,A里有一個fragment,fragment里有一個按鈕,可以跳轉到Activity B。
我們打開不保存狀態,點擊fragment里的按鈕跳轉到B,然后返回,看看A以及fragment的哪些生命周期調用了
看看log的打印信息:
test是在onSavedInstanceState中保存的字符串
我們可以看到:
Fragment被創建兩次。
第二次創建的fragment獲取不到我們保存的狀態。
想一想也是有道理的:
在不保存狀態的情況下,跳轉到B之后,A和A里面的fragment都被銷毀了,回到A的時候,log中打印的第一個fragment是系統保存狀態然后恢復的fragment,所以保存的狀態都能獲取到,但是第二個fragment是在恢復activity運行生命周期onCreate方法的時候我們代碼new出來的,所以第二個fragment里面是沒有我們之前保存的狀態的。
這種問題要怎么解決呢?
如果只是解決問題1,重復創建fragment的情況(不想有兩個fragment實例,因為有的如果是透明fragment可能還會出現重疊),很好解決使用replace,或者不調用fragment的super.onSavedInsance()等等。
但是如果我們想要在fragment中保存狀態要怎么辦呢?
如果是一個fragment的activity,我們可以先從fragmentManager里去取,如果取到了,那么說明這個fragment已經有了,那么我們就什么也不做,如果沒取到,我們再去創建。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.e("StateActivity", "---------------onCreate");
setContentView(R.layout.activity_main_for_state);
FragmentManager fm = getSupportFragmentManager();
Fragment1 f = (Fragment1) fm.findFragmentByTag(TAG_FRAGMENT1);
if (f == null) {
FragmentTransaction ft = fm.beginTransaction();
f = Fragment1.newInstance("", "");
ft.add(R.id.state_fragment_container, f, TAG_FRAGMENT1);
ft.commit();
}
}
再來運行一下看看log:
Fragment只被創建了一次,并且也能獲取到他所保存的狀態。
(其實也可以根據savedInstanceState是否為空來判斷是否需要重新創建fragment。)
如果一個activity里需要創建多個fragment并且以tab的方式來切換,我們應該怎么做?
借鑒fragmentTabHost里的做法,用一個TabInfo實體類來保存對應的tab和fragment之間的關系。對于fragment的創建,還是先從fragmentManager里去取,如果沒有再去創建。
使用一個TabInfo實體類來保存fragment和每個tab之間的關系。
比如:
public class TabInfo {
public final String tag;
public final Class<? extends Fragment> clazz;
public final int viewId;
public TabInfo(String tag, Class<? extends Fragment> clazz, int viewId) {
this.tag = tag;
this.clazz = clazz;
this.viewId = viewId;
}
}
然后用一個list來保存所有的tab信息:
private ArrayList<TabInfo> tabInfos = new ArrayList<TabInfo>(2);
//在onCreate()中初始化tab
tabInfos.add(new TabInfo(Fragment1.class.getSimpleName(), Fragment1.class, R.id.tab_right));
tabInfos.add(new TabInfo(Fragment2.class.getSimpleName(), Fragment2.class, R.id.tab_left));
當然這里做的比較粗糙,使用兩個按鈕做tab,也可以使用其他的自定義view。
切換的時候
private void switchTab(int tabIndex) {
TabInfo tabInfo = tabInfos.get(tabIndex);
FragmentManager fm = getSupportFragmentManager();
Fragment f = fm.findFragmentByTag(tabInfo.tag);
FragmentTransaction transaction = fm.beginTransaction();
if (f == null) {
f = Fragment.instantiate(this, tabInfo.clazz.getName());
transaction.add(R.id.tab_fragment_container, f, tabInfo.tag);
}
if (currentFragment != null && currentFragment != f) {
transaction.hide(currentFragment);
}
transaction.show(f);
transaction.commit();
currentFragment = f;
this.tabIndex = tabIndex;
}
這里替換fragment用的是show/hide(不銷毀fragment和視圖),當然你也可以使用detach/attach(只銷毀視圖不銷毀fragment實例)
http://www.voidcn.com/blog/u013168615/article/p-5794851.html(這篇文章講show/hide,detach/attach等等比較詳細)
再來看看我們的log:
一切正常!