10

我有一個很大的問題,我不完全理解發生了什麼。我正在開發一個使用Fragments(來自支持庫)的應用程序,並且正在使用FragmentTransaction.replace()將新碎片放在後端堆棧上並替換舊碎片。代碼如下:Android片段查看狀態使用FragmentTransaction.replace時丟失()

FragmentManager fm = getSupportFragmentManager(); 
FragmentTransaction ft = ft.beginTransaction(); 
// Animations in my res/anim folder 
ft.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left, R.anim.slide_in_left, R.anim.slide_out_right); 
ft.replace(R.id.fragment_container, newFragment, tag); 
ft.addToBackStack(null); 
ft.commit(); 

這是成功地取代我的片段。我的問題如下。在一個片段中,我有一個從用戶輸入構建的項目列表。現在,當用戶單擊下一個然後單擊後退按鈕(返回列表)時,列表爲空,因爲視圖已被銷燬。現在,我注意到以下幾點:

  1. onSaveInstanceState未被調用。我相信這是因爲只有在父活動告訴它時纔會調用它。基於文檔:「在很多情況下,碎片可能大部分被拆除(例如,當放置在背堆棧上而沒有UI顯示時),但是其狀態不會被保存,直到其擁有的活動實際上需要保存其狀態「。顯然,在FragmentTransaction上執行替換並不是那些時間之一。有沒有人有這方面的確認或更好的解釋?
  2. setOnRetainInstanceState(true)在這種情況下沒有幫助。再次,我認爲這與來自文檔的信息有關:「控制是否在重新創建Activity(例如從配置更改)中保留片段實例」。我在重新創建活動時沒有執行任何操作,所以這沒用。

所以,我想我的主要問題是:有沒有辦法在使用replace時保留視圖狀態(僅保留片段)?有FragmentTransaction.add(),但也有一些問題。一種是不執行退出動畫,因此動畫不正確。另一個原因是舊片段(即被置於不可見狀態的片段)仍然可點擊的新片段。例如,如果我有一個ListFragment,並且使用add將一個內容片段放在頂部,我仍然可以單擊ListFragment中的列表項。

回答

2

不能看到你的片段的代碼這是一個猜測,但在過去我遇到了同樣的問題,我發現重置在適配器似乎做的伎倆。

public void onViewStateRestored (Bundle savedInstanceState) 
{ 
    super.onViewStateRestored (savedInstanceState); 
    setListAdapter(new ArrayAdapter(Activity, R.layout.nav_item, objects)); 
} 

這是奇怪的考慮文檔指出這種方法onActivityCreated之後,但onStart之前調用。但似乎它在其他時候也被調用,因爲當最近的片段事務從背堆棧彈出時,在顯示先前替換的片斷之前調用此方法。擁有這些片段的活動並未以任何方式暫停或遮蓋,因此根據文檔onViewStateRestored不應調用,因爲片段已被修改。但是,無論如何,這似乎工作。

2

這聽起來像你只需要確保你已經正確實現onCreateView和onDestroyView。你所描述的情況似乎表明,當列表片段被放在後端堆棧上時(作爲替換事務的結果),Android正在調用onDestroyView來釋放一些資源。但是,它顯然沒有銷燬列表片段,因爲當你點擊回來的時候你會得到相同的片段實例。

假設這一切都是真的,那麼當用戶點擊後,Android會調用onCreateView。你存儲在片段的實例變量中的任何狀態都應該在那裏,你需要做的就是重新填充視圖...也許在ListView上設置適配器或其他。

還要確保您的onSaveInstanceState()回調實際上確實保存了您需要重建視圖的任何實例狀態。這樣,如果片段實際上完全銷燬,FragmentManager可以在需要稍後重新創建片段時恢復狀態。