2014-09-12 79 views
4

在我的開源Android應用程序中,發現了一個問題,即在特定情況下特定片段會在另一個片段的頂部進入視圖或崩潰應用程序。正確/最好的方式來處理Android片段交易問題

在GitHub上,如果你想看到更多的信息,例如屏幕截圖中的問題: https://github.com/rpi-mobile/RPIMobile-Android/issues/31

我有牽制的原因,但想知道哪些在android.support.v4.app包的方法用來解決問題。

MainActivity.java中,是導航抽屜的代碼,它使用FragmentTransaction.replace()來切換片段。

問題的產生是因爲在MapFragment,我使用:

ViewMapFragment vmf = new ViewMapFragment(); 
FragmentTransaction ft = getSherlockActivity().getSupportFragmentManager().beginTransaction(); 
ft.addToBackStack(null); 
ft.replace(R.id.content_frame, vmf); 
ft.commit(); 

而且在ViewMapFragmentonDestroyView()

FragmentManager fm = getSherlockActivity().getSupportFragmentManager(); 
FragmentTransaction ft = fm.beginTransaction(); 
ft.remove(fm.findFragmentById(R.id.mapview)); 
ft.commit(); 

onDestroyView()正確去除鑑於ViewMapFragment,但如果你擁有了它在查看和使用導航抽屜改變到不同的片段,MapFragment仍然在後面的堆棧上。

所以,我的問題:

1)如何檢查如果一個特定的片段後棧試圖刪除/更換之前,或者如果您嘗試沒事的時候是將應用程序不會崩潰有(即不檢查)?例如。當背面堆棧上沒有任何東西時調用popBackStack()

2)我是否應該使用FragmentManager類方法嘗試從背堆棧中刪除MapFragment,或者我應該使用FragmentTransaction方法?優點vs缺點?

3)popBackStack()popBackStackImmediate()之間的界面有什麼不同?用戶是否看到一些令人毛骨悚然的轉變?

回答

4

根據FragmentTransaction的文檔,當您調用addToBackStack方法時,它只會記住您在該事務中執行的操作。當調用popBackStack方法時,它將反轉這些操作並執行它們。

那麼,會發生什麼:

  1. 當我們從MapFragment去ViewMapFragment,FragmentManager記得刪除MapFragment和添加ViewMapFragment操作。
  2. 然後,我們使用Navigation Drawer導航到任何其他片段,導致ViewMapFragment刪除操作,然後添加從Drawer中選擇的片段。
  3. 最後,當我們按下Back按鈕時,popBackStackImmediate被調用,FragmentManager執行反向操作:ViewMapFragment被刪除(實際上它已經被刪除)並添加了MapFragment。這裏是問題發生 - 選定的片段仍然存在,所以我們同時在屏幕上有兩個片段。

有幾個選項來處理這樣的情況:

  1. 只需添加抽屜式導航操作來支持堆疊。
  2. 每次由導航抽屜啓動碎片切換時清除堆棧。

要清除後退堆棧,你可以使用此代碼(related question):如果你把這個線你選擇信息的方法開始的錯誤會被修正

getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); 

而且您的問題:

  1. 可以檢查片段是否處於後堆棧使用FragmentManager.findFragmentByTag方法。請參閱我的答案結尾處的示例。
  2. 從技術上說,背堆棧的條目可以包含多個片段,我不認爲有辦法從中刪除單個片段。而不是刪除你可以清除堆棧(請參閱此question)。
  3. 主要區別在於popBackStack會給你一個機會做一些事情,然後它纔會真正開始彈出過程(it will be started when application returns to it's event loop)。

例子。例如,我們添加了一個標籤「片段1」的片段:

getSupportFragmentManager() 
     .beginTransaction() 
     .replace(R.id.frame, new TestFragment(), "fragment-1") 
     .commit(); 

然後,我們把它變成一個後退堆棧,並與另一個片段取代它:

getSupportFragmentManager() 
     .beginTransaction() 
     .addToBackStack(null) 
     .replace(R.id.frame, new TestFragment(), "another-fragment") 
     .commit(); 

此時getSupportFragmentManager ().findFragmentByTag(「fragment-1」)返回我們的第一個片段(它從背堆棧條目中獲取它)。現在我們可以通過isAdded方法來檢查這個片段是否被添加到了它的活動中 - 如果它返回false,那麼我們可以假設這個片段是在後退堆棧中。

+0

謝謝你的回答!我將使用您的一線解決方案。作爲對你答案的反饋,除了間接地回答問題2,你沒有完全回答問題1,而你對問題2的回答可能會稍微更具體一些,以便在關聯答案中查找的位置,因爲我必須梳理關於該問題的評論頁。 – pdpiech 2014-09-14 00:13:47

+0

不幸的是,這個問題沒有一個好的解決方案(在API中使用clearBackstack方法會很好,但是沒有這種方法)。我必須在我的項目中實現我自己的後退堆棧系統,因爲這個問題和轉換故障,同時清除後臺堆棧(我使用相當自定義的轉換動畫)。 :( – Ayzen 2014-09-14 10:23:09

+0

我已經添加了更多關於1&2問題的信息。希望這有幫助。 – Ayzen 2014-09-14 12:01:22