正確創(chuàng)建Fragment的姿勢

如果出現(xiàn)fragment中onSavedInstanceState中保存的狀態(tài)在fragment再次創(chuàng)建的時候無法獲取皿淋,那么這篇文章正是你想要的站楚。

我們很多應用都是由下面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里需要保存狀態(tài)那就有問題了蹭秋。
我們有A,B兩個Activity堤撵,A里有一個fragment仁讨,fragment里有一個按鈕,可以跳轉(zhuǎn)到Activity B实昨。
我們打開不保存狀態(tài)洞豁,點擊fragment里的按鈕跳轉(zhuǎn)到B,然后返回,看看A以及fragment的哪些生命周期調(diào)用了
看看log的打印信息:


test是在onSavedInstanceState中保存的字符串

我們可以看到:
Fragment被創(chuàng)建兩次丈挟。
第二次創(chuàng)建的fragment獲取不到我們保存的狀態(tài)闰挡。

想一想也是有道理的:
在不保存狀態(tài)的情況下,跳轉(zhuǎn)到B之后礁哄,A和A里面的fragment都被銷毀了,回到A的時候溪北,log中打印的第一個fragment是系統(tǒng)保存狀態(tài)然后恢復的fragment桐绒,所以保存的狀態(tài)都能獲取到,但是第二個fragment是在恢復activity運行生命周期onCreate方法的時候我們代碼new出來的之拨,所以第二個fragment里面是沒有我們之前保存的狀態(tài)的茉继。

這種問題要怎么解決呢?
如果只是解決問題1蚀乔,重復創(chuàng)建fragment的情況(不想有兩個fragment實例烁竭,因為有的如果是透明fragment可能還會出現(xiàn)重疊),很好解決使用replace吉挣,或者不調(diào)用fragment的super.onSavedInsance()等等派撕。

但是如果我們想要在fragment中保存狀態(tài)要怎么辦呢?

如果是一個fragment的activity睬魂,我們可以先從fragmentManager里去取终吼,如果取到了,那么說明這個fragment已經(jīng)有了氯哮,那么我們就什么也不做际跪,如果沒取到,我們再去創(chuàng)建喉钢。

@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只被創(chuàng)建了一次姆打,并且也能獲取到他所保存的狀態(tài)。
(其實也可以根據(jù)savedInstanceState是否為空來判斷是否需要重新創(chuàng)建fragment肠虽。)

如果一個activity里需要創(chuàng)建多個fragment并且以tab的方式來切換幔戏,我們應該怎么做?

借鑒fragmentTabHost里的做法税课,用一個TabInfo實體類來保存對應的tab和fragment之間的關(guān)系评抚。對于fragment的創(chuàng)建,還是先從fragmentManager里去取伯复,如果沒有再去創(chuàng)建慨代。

使用一個TabInfo實體類來保存fragment和每個tab之間的關(guān)系。
比如:

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:


一切正常妇汗!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市说莫,隨后出現(xiàn)的幾起案子杨箭,更是在濱河造成了極大的恐慌,老刑警劉巖储狭,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件互婿,死亡現(xiàn)場離奇詭異,居然都是意外死亡辽狈,警方通過查閱死者的電腦和手機慈参,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來刮萌,“玉大人驮配,你說我怎么就攤上這事∽湃祝” “怎么了壮锻?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長涮阔。 經(jīng)常有香客問我躯保,道長,這世上最難降的妖魔是什么澎语? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任途事,我火速辦了婚禮,結(jié)果婚禮上擅羞,老公的妹妹穿的比我還像新娘尸变。我一直安慰自己,他們只是感情好减俏,可當我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布召烂。 她就那樣靜靜地躺著,像睡著了一般娃承。 火紅的嫁衣襯著肌膚如雪奏夫。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天历筝,我揣著相機與錄音酗昼,去河邊找鬼。 笑死梳猪,一個胖子當著我的面吹牛麻削,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼呛哟,長吁一口氣:“原來是場噩夢啊……” “哼叠荠!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起扫责,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤榛鼎,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后鳖孤,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體者娱,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年淌铐,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蔫缸。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡腿准,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出拾碌,到底是詐尸還是另有隱情吐葱,我是刑警寧澤,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布鼓蜒,位于F島的核電站优幸,受9級特大地震影響添寺,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜孟辑,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蔫敲。 院中可真熱鬧饲嗽,春花似錦、人聲如沸奈嘿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽裙犹。三九已至尽狠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間叶圃,已是汗流浹背袄膏。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留掺冠,地道東北人哩陕。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親悍及。 傳聞我的和親對象是個殘疾皇子闽瓢,可洞房花燭夜當晚...
    茶點故事閱讀 43,486評論 2 348

推薦閱讀更多精彩內(nèi)容