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(); 

那么,如果已经自动添加的片段,新的片段将只需更换它在视图中。