支持FragmentManager、popbackstack和屏幕旋转

Mar*_*een 4 android android-fragments

我有一个奇怪的问题让我发疯!

设想:

我有ActivityA 作为启动器Activity, B 可以通过inActivity启动IntentActivity A

Activity A --> Activity B
Run Code Online (Sandbox Code Playgroud)

Activity B 有一个初始Fragment名称为FragmentC,它在 B 中实例化,Activity如下所示:

if(getSupportFragmentManager().findFragmentByTag(FragmentC.TAG) == null) {
        getSupportFragmentManager()
                 .beginTransaction()
                 .add(R.id.container,
                  FragmentC.newInstance(null), // optional bundle
                  FragmentC.TAG)
                 .commit();
}
Run Code Online (Sandbox Code Playgroud)

FragmentCI 中,有一个RecyclerViewOnClickListenerthis 上通过CViewHolder回调到托管B。此时,我启动一个(在B 中)来替换当前的C,将其称为D,然后将此事务添加到后台堆栈:ActivityFragmentFragmentTransactionActivityFragmentFragment

getSupportFragmentManager()
          .beginTransaction()
          .setCustomAnimations(
                  R.anim.fragment_slide_enter,
                  R.anim.fragment_slide_exit,
                  R.anim.fragment_slide_enter_pop,
                  R.anim.fragment_slide_exit_pop)
          .replace(R.id.container,
                        FragmentD.newInstance(bundle),
                        FragmentD.TAG)
          .addToBackStack(null)
          .commit();
Run Code Online (Sandbox Code Playgroud)

所以此时我有ActivityB 和D 以及从C 到DFragment的事务在后堆栈中,处理后按如下所示:FragmentFragment

@Override
public boolean onSupportNavigateUp() {
    onBackPressed();
    return true;
}

@Override
public void onBackPressed() {
    super.onBackPressed();
}
Run Code Online (Sandbox Code Playgroud)

导航可以正确地向前和向后,从ActvityA 开始,到ActivityB --> FragmentD 并返回。

问题:

但是,如果我在FragmentD 中并旋转屏幕,则pop返回堆栈将转到FragmentC(撤消事务),我会看到一个空白Fragment。更奇怪的是,C的所有生命Fragment周期方法OnCreate()、、都被调用,并且我有有效的数据/对象(通过设置断点检查)。OnCreateView()OnActivityCreated()

然而奇怪的是,如果我add在从FragmentC --> FragmentD 进行交易时,显然两者同时显示在彼此之上,并且我旋转屏幕并按回并删除交易,则没有问题,显然不是解决方案,只是一个观察。

我已经搜索过,但我读过和尝试过的所有内容都不起作用。我之前已经实现过类似的东西,效果很好,但我在这里很挣扎 - 任何帮助将不胜感激。

编辑

如果应用程序进入暂停状态(单独放置并且屏幕关闭),然后再次唤醒并恢复,则 Fragment 将按其应有的方式显示。我没有初始化,onResume所以我不知道为什么会这样。

Mar*_*een 5

问题解决了

好的,感谢您的建议,但我自己已经解决了问题。

解决方案?非常简单,我在踢自己!

当弹出后台堆栈时,我从未将“pop”包含getId()在内:Fragment

之前的代码依靠 来FragmentActivity弹出 backstack 本身onBackPressed()。事实上,文档和方法应该解决这个问题:

/**
 * Take care of popping the fragment back stack or finishing the activity
 * as appropriate.
 */
@Override
public void onBackPressed() {
     if (!mFragments.getSupportFragmentManager().popBackStackImmediate()) {
            super.onBackPressed();
      }
}
Run Code Online (Sandbox Code Playgroud)

然而,当配置发生更改并且您想要将返回堆栈弹出到上一个事务时,这似乎无法正常工作。代码解决方案是我自己手动“弹出”返回堆栈:

前:

@Override
public boolean onSupportNavigateUp() {
    onBackPressed();
    return true;
}

@Override
public void onBackPressed() {
    super.onBackPressed();
}
Run Code Online (Sandbox Code Playgroud)

之后(工作解决方案):

@Override
public boolean onSupportNavigateUp() {
    onBackPressed();
    return true;
}

@Override
public void onBackPressed() {
    if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
            getSupportFragmentManager().popBackStack(getSupportFragmentManager()
                    .getBackStackEntryAt(0).getId(), 
                    FragmentManager.POP_BACK_STACK_INCLUSIVE));
    } else {
            super.onBackPressed();
    }
 }
Run Code Online (Sandbox Code Playgroud)

状态的文档getId()

/**
 * Return the unique identifier for the entry.  This is the only
 * representation of the entry that will persist across activity
 * instances.
 */
public int getId();
Run Code Online (Sandbox Code Playgroud)

因此,基本上,在发生配置更改(托管已被销毁并重新创建)后成功“弹出”后堆栈的唯一方法Activity是引用Fragments唯一的id.