12

我有一個非常奇怪的問題與片段。我使用最新的支持庫。我也使用谷歌使用的類似代碼IOSCHED projectAndroid:使用支持片段管理器時複製片段

但是我在旋轉後重新創建活動時遇到了問題。在活動被銷燬並重新創建後,我調用管理片段事務的方法(在onStart方法中)。這行只被調用一次,但它會創建片段TWICE!

這是我的活動方法:

public abstract class SinglePaneActivity extends FragmentActivity 
{ 
    @Override 
    protected void onStart() 
    { 
     super.onStart(); 

     if(mFragment == null) 
     { 
      mFragment = onCreatePane();  
      mFragment.setArguments(Utils.intentToFragmentArguments(getIntent())); 

      Log.w(TAG, "Fragment creation counter = " + createCounter); 
      createCounter++; 

      getSupportFragmentManager() 
      .beginTransaction() 
      .add(R.id.root_container,mFragment) 
      .commit(); 
     } 
    } 

    @Override 
    protected void onStop() 
    { 
     Log.i(TAG, "onStop"); 
     if(mFragment != null) 
     { 
      getSupportFragmentManager() 
      .beginTransaction() 
      .remove(mFragment) 
      .commit(); 

      mFragment = null; 
     } 
     super.onStop(); 
    } 
} 

和我的日誌:

--Start of application-- 
11-18 13:26:37.050: I/SinglePaneActivity(19040): onCreate 
11-18 13:26:37.050: I/SinglePaneActivity(19040): onStart 
11-18 13:26:37.055: W/SinglePaneActivity(19040): replacing fragment, counter = 1 
11-18 13:26:37.075: I/MyFragment(19040): onCreate 
11-18 13:26:37.110: I/MyFragment(19040): onActivityCreated 
--Rotating the device-- 
11-18 13:26:39.600: I/SinglePaneActivity(19040): onStop 
11-18 13:26:39.600: I/SinglePaneActivity(19040): onDestroy 
11-18 13:26:39.605: I/MyFragment(19040): onDestroy 
11-18 13:26:39.755: I/MyFragment(19040): onCreate 
11-18 13:26:39.755: I/SinglePaneActivity(19040): onCreate 
11-18 13:26:39.790: I/MyFragment(19040): onActivityCreated 
11-18 13:26:39.800: I/SinglePaneActivity(19040): onStart 
11-18 13:26:39.800: W/SinglePaneActivity(19040): replacing fragment, counter = 2 
11-18 13:26:39.810: I/MyFragment(19040): onCreate 
11-18 13:26:39.815: I/MyFragment(19040): onActivityCreated 
--Rotating the device back-- 
11-18 13:36:47.060: I/SinglePaneActivity(19040): onStop 
11-18 13:36:47.060: I/SinglePaneActivity(19040): onDestroy 
11-18 13:36:47.060: I/MyFragment(19040): onDestroy 
11-18 13:36:47.065: I/MyFragment(19040): onDestroy 
11-18 13:36:47.130: I/MyFragment(19040): onCreate 
11-18 13:36:47.130: I/MyFragment(19040): onCreate 
11-18 13:36:47.130: I/SinglePaneActivity(19040): onCreate 
11-18 13:36:47.140: I/MyFragment(19040): onActivityCreated 
11-18 13:36:47.150: I/MyFragment(19040): onActivityCreated 
11-18 13:36:47.150: I/SinglePaneActivity(19040): onStart 
11-18 13:36:47.150: W/SinglePaneActivity(19040): replacing fragment, counter = 3 
11-18 13:36:47.160: I/MyFragment(19040): onCreate 
11-18 13:36:47.160: I/MyFragment(19040): onActivityCreated 
--Exiting the app-- 
11-18 13:36:48.880: I/SinglePaneActivity(19040): onStop 
11-18 13:36:48.885: I/SinglePaneActivity(19040): onDestroy 
11-18 13:36:48.885: I/MyFragment(19040): onDestroy 
11-18 13:36:48.890: I/MyFragment(19040): onDestroy 
11-18 13:36:48.890: I/MyFragment(19040): onDestroy 

所以碎片的數量每次旋轉後增長。

旋轉之後,它將在片段進入我的onStart方法之前恢復片段,並且我的onStart方法將在同一個Frame佈局容器中創建第二個相同的片段。但是它在哪裏恢復第一個片段?我想要推斷它。或者我應該改變我的「如果」來測試它是否已經創建?但我不知道如何確定它。它看起來空測試是無用的。

我也通過用replace()代替add()方法做出小的解決方法。之後,碎片的數量不會增加,並且在創建新方法之前,每個碎片都會被銷燬。但是,這使得一些片段中的嚴重問題,我開始在他們的創建方法的一些後臺進程...

請幫助我...我真的不知道如何處理它。非常感謝您提供任何建議或意見!

回答

23

那麼我找到了一個解決方案。我必須將片段管理器的代碼從onStart移動到onCreate,並檢查null的值savedInstanceState。那麼我不知道它是自動保存並從savedInstanceState恢復。很高興知道!

編輯: 而要做到這一點完全正確的,即恢復片段時savedInstanceState不爲空,應該有:

if(savedInstanceState == null) 
    { 
     mFragment = onCreatePane();  
     mFragment.setArguments(Utils.intentToFragmentArguments(getIntent())); 

     getSupportFragmentManager() 
     .beginTransaction() 
     .add(R.id.root_container,mFragment) 
     .commit(); 
    } 
    else 
    { 
     mFragment = getSupportFragmentManager().findFragmentById(R.id.root_container); 
    } 
+0

是的!謝謝。我一直在努力解決同樣的問題。在我的Activity中檢查了一個null savedInstanceState,然後加載我的片段做了訣竅 – Chiatar

-1

或者,如果您的片段不補繳堆棧:setRetainInstance(true);

+1

這不被鼓勵。如果片段持有任何對活動實例的引用;直接或通過諸如視圖等成員,這會導致內存泄漏。 – frostymarvelous

1

我有一個類似的問題,但我從一個父級片段添加一個孩子片段,並看到一個重複的孩子片段。我試圖將其添加到父片段的onStart中,以便可以訪問父視圖,該視圖在onCreate中不可用。因此,我沒有將代碼移到onCreate,而是將它移動到onActivityCreated;該方法可以訪問父視圖,並且還可以訪問savedInstanceState變量以檢查片段是否已被自動添加。從活動添加片段時這不是問題,因爲活動的視圖在onCreate中可用。


如果由於某種原因,你需要在onStart或其他地方savedInstanceState不可添加一個片段,這裏是一個另類。使用原問題的onStart代碼...

if(mFragment == null) 
    { 
     mFragment = onCreatePane();  
     mFragment.setArguments(Utils.intentToFragmentArguments(getIntent())); 

     Log.w(TAG, "Fragment creation counter = " + createCounter); 
     createCounter++; 

     getSupportFragmentManager() 
     .beginTransaction() 
     .add(R.id.root_container,mFragment) 
     .commit(); 
    } 

...你可以replace而非add片段:

if(mFragment == null) 
    { 
     mFragment = onCreatePane();  
     mFragment.setArguments(Utils.intentToFragmentArguments(getIntent())); 

     Log.w(TAG, "Fragment creation counter = " + createCounter); 
     createCounter++; 
    } 

    getSupportFragmentManager() 
    .beginTransaction() 
    .replace(R.id.root_container,mFragment) 
    .commit(); 

那麼,如果已經自動添加的片段,新的片段將只需更換它在視圖中。