【问题标题】:Fragment overlaps on activity rotation活动轮换上的片段重叠
【发布时间】:2013-03-08 09:32:50
【问题描述】:

我对此感到非常困惑。我有一个带有列表导航的actionbar。我点击列表依次打开2个fragment并显示在同一个活动中。我基本上是用这种方法替换它们:

public void openFragment(AprilAppsFragment createdFragment){        
    if (createdFragment.getClass().isInstance(getDisplayedFragment()))
        return;

    FragmentManager manager = getSupportFragmentManager();
    FragmentTransaction transaction = manager.beginTransaction();
    transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);

    transaction.replace( R.id.main_fragment, createdFragment, "displayed fragment"); 
    transaction.addToBackStack(null);
    transaction.commit();  
}

我打开片段A,然后打开片段B,然后旋转屏幕。正在重新创建片段 A 导致我的应用崩溃

为什么会这样,因为我使用的是替换?如何避免重新创建不再显示的片段,同时又不会失去对它们进行反压的可能性?

【问题讨论】:

  • 你能从崩溃中添加堆栈跟踪吗?
  • 这无关紧要。当片段尝试用数据填充其内容时发生崩溃,但它无法实例化视图组件,因为它甚至没有显示
  • 您是否从OnNavigationListener 调用该方法?如果是,请记住监听器将由活动创建/重新创建触发。
  • if (createdFragment.getClass().isInstance(getDisplayedFragment())) return; 的声明很可疑。你能告诉我们堆栈跟踪吗?堆栈跟踪永远不会无关紧要。

标签: android android-fragments


【解决方案1】:

你的问题是你没有为你的片段保存状态,因为你还没有添加

android:configChanges="orientation|screenSize"

您的第一个片段再次被调用,由于您没有保存状态,您的应用程序崩溃。因此,您可以在清单中的 Activity 声明中添加上面的行,例如:

<activity android:name=".yourActivity" android:configChanges="orientation|screenSize"

并覆盖 onSaveInstanceState 并保存两个片段的状态。在你的 onCreate 中做这个检查:

if(savedInstanceState != null){
fragmentA = (FragmentA) fragmentManager.getFragment(savedInstanceState, stringValueA);
fragmentB = (FragmentB) fragmentManager.getFragment(savedInstanceState, stringValueB);
}

然后检查您的任何片段是否不为空,然后创建其实例并将其设置为 fragmentTransaction.relplace。或者在您的 for openFragment 方法中执行此操作。

干杯,

【讨论】:

  • 它并没有真正回答为什么娱乐活动会重新创建所有片段,即使是那些被替换的片段。 configChanges 实际上停止了娱乐活动,但它不适用于 ActionBarSherlock,我只值得在后 ICS 系统上尝试
  • 阅读本帖中的答案:stackoverflow.com/questions/14184182/…
  • 这样一个恼人的问题通常不会用一行代码来解决,但是你去吧。谢谢,@AliR。
【解决方案2】:

片段在旋转时会自动保存它们的状态(以及后堆栈上的位置)。确保您没有在 onActivityCreated 或 onCreate 方法中重新创建片段或调用 openFragment。

【讨论】:

  • 那么您创建片段 A 和片段 B(即调用此 openFragment 方法)的唯一位置是在列表的点击方法中?
  • 没错,只有这个地方
【解决方案3】:

您的问题是您的活动正在重新创建,这导致您重新设置列表导航,这导致触发默认(第一个)位置。您需要在活动销毁和活动重新创建之间保存选定的索引。这是一个例子:

@Override
public void onCreate(Bundle savedInstanceState) {

    // onCreate implementation...

    // Must come after setListNavigationCallbacks is called
    if (savedInstanceState != null) {
        int index = savedInstanceState.getInt("index");
        getActionBar().setSelectedNavigationItem(index);
    }
}

@Override
protected void onSaveInstanceState(Bundle outState) {

    super.onSaveInstanceState(outState);
    outState.putInt("index", getActionBar().getSelectedNavigationIndex());
}

【讨论】:

    【解决方案4】:

    我遇到了类似的问题,我要做的是在我的 Androidmanifest.xml(在您想要停止的活动中重新创建):

    android:configChanges="orientation"

    还有一件事,我了解到片段是一种子活动,而不是活动, 我们必须扩展一个Activity Fragment以获得对Fragment的支持,而扩展该Activity Fragment的Activity实际上是持有一个称为Fragment的“子活动”的Activity。

    希望能帮到你……

    【讨论】:

      【解决方案5】:

      将此添加到您的 AndroidManifest.xml 文件中的活动定义中:

      android:configChanges="keyboardHidden|screenLayout|orientation|screenSize"
      

      这将阻止 Activity 重新启动,并且 FragmentManager 不会自动重新创建它拥有的片段。

      如果您需要在旋转时重新启动 Activity,那么您必须查找已传递给 onCreate 的 savedInstanceState,然后使用您提供的标签查询 FragmentManager 以获取您的片段。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多