旋转屏幕时Fragment未被销毁

6

我有一个通过编程方式添加的片段。然而,我发现在旋转之后,新的片段被创建,但旧的片段仍然存在(尽管没有显示)。我认为在旋转时,片段会随着活动一起被销毁,但这里并非如此。是什么导致我的片段被保留/未被销毁?

请注意:

  1. 我没有设置setRetainInstance。
  2. 片段未在activity onCreate中添加(而是在稍后点击按钮时添加)。
  3. 我可以看到Activity在旋转时调用了onDestroy。
  4. 虽然片段已经添加,它遮挡了添加按钮,并且只有在我执行“remove”操作时才会被解除。

创建该片段的代码:

MyFragment fragment = MyFragment();
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.content_frame, fragment, "CurrentFragment");
fragmentTransaction.show(fragment).commit();

移除片段的代码:

FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.remove(fragment).commit();

更新: 我不能确认这是否是问题的原因,但是该碎片在onCreate中注册为LocalBroadcast接收器。它在onDestroy中注销广播,但似乎LocalBroadcast注册导致了onDestroy无法被调用,或者旋转时没有调用onDestroy。现在我在onStop中注销,这似乎解决了问题。


当您旋转设备时,那个由按钮按下添加的片段是否显示? - M-Wajeeh
@M-WaJeEh 是的,新创建的片段已显示。 - RunLoop
5个回答

16
当Activity因为屏幕方向改变而重新启动时,Android框架会自动重新创建并添加Fragment。你可能会在Activity的onCreate中添加Fragment。在屏幕方向改变后,你可能会添加另一个Fragment。
你需要检查是否已经添加了该Fragment:
Fragment f = getFragmentManager().findFragmentById(R.id.content_frame);
if(f == null){
    //Add it, there is no Fragment
}else{
    //It's already there
}
每次点击添加 Fragment 的按钮时,都会添加一个新的 Fragment。如果你的容器是 FrameLayout,可能看不到它。尝试替换 Fragments:
fragmentTransaction.replace(R.id.content_frame, fragment, "CurrentFragment");

方法setRetainInstance(true)还有另一个目的。如果启用了它,Fragment实例将在方向改变时不会被销毁(但其视图将被销毁)。这意味着您可以将数据存储在Fragment的成员变量中,并且在方向更改后该数据仍将可用。

当设置setRetainInstance(true)时,Fragment的生命周期会稍有不同。即onCreate()onDestroy()不会被调用(因为这些事件不会发生)。


@Hermann 我没有在onCreate中添加片段。当用户点击按钮时,它会被添加。 - RunLoop
您在旋转之前是否按下了按钮多次? - thaussma

2

在 Activity 被销毁之前,您的片段可能会被保存在 Bundle 对象中。尝试在 onSaveInstanceState() 中处理删除片段:

@Override
    protected void onSaveInstanceState(Bundle outState) {
        //remove here fragments
        super.onSaveInstanceState(outState);
    }

或者你可以在onCreate()中将Bundle设置为null:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        savedInstanceState = null;
        super.onCreate(savedInstanceState);
    }

那个 null 赋值只是将该句柄的副本指向空。你可能指的是 savedInstanceState.clear() - homerman

2

为什么不能使用想要加载的新片段替换现有片段。

尝试这个,可能会有所帮助。

FragmentNew mFragmentNew = new FragmentNew ();// Which you want to load That Fragment Object 
        getFragmentManager().beginTransaction()
                .replace(R.id.item_detail_container, mFragmentNew)
                .commit();

1

我曾经遇到过这个问题,解决方法是替换这行代码

fragmentTransaction.add(R.id.content_frame, fragment, "CurrentFragment");

fragmentTransaction.replace(R.id.content_frame, fragment, "CurrentFragment");

享受


0

在第一次启动时,您只需要添加Fragment一次,像这样操作: 以下代码是从http://developer.android.com/reference/android/app/Fragment.html复制的,注释是我的:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);


    // My Comment: only add when launched for the first time, it won't be null on orientation change
    if (savedInstanceState == null) {
        // During initial setup, plug in the details fragment.
        DetailsFragment details = new DetailsFragment();
        details.setArguments(getIntent().getExtras());
        getFragmentManager().beginTransaction().add(android.R.id.content, details).commit();
    }
}

我不会在onCreate中添加片段。它会在用户点击按钮时添加。 - RunLoop

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接