如何在活动中恢复片段后堆栈(在应用程序在后台被杀死后)

16
在一个 Android 应用程序中 -
假设我在一个 Activity - MyActivity 中,每次只会加载一个 Fragment。
首先我将 Fragment A 加载到其中(没有标签,我将其添加到 FragmentManager 的后退堆栈中)
然后在某个时间点,我加载了 Fragment B(同样没有标签,我将其添加到 FragmentManager 的后退堆栈中)
然后在某个时间点,我加载了 Fragment C(同样没有标签,我将其添加到 FragmentManager 的后退堆栈中)
我使用 popBackStack() 来启用“返回按钮”行为,因此每当我从 Fragment C 按返回键时,流程如下:
Fragment C -> Fragment B -> Fragment A -> 关闭 MyActivity。。
一切都很完美 :-)
但是如果我在 Fragment C 中并且应用程序在后台被杀死(我在设置中使用了“不保留活动标志”)
并且重新联机后,Fragment C 就会加载到 MyActivity 中,
但是 FragmentManager 的后退堆栈仅包含 Fragment C。。
返回按钮会导致它出现问题
Fragment C -> 关闭 MyActivity。。
为什么会这样?
如何正确恢复 Activity 内的 FragmentManager 的后退堆栈?

这可能是因为您的活动被杀死并且失去了所有引用。如果您愿意,可以创建自己的后退堆栈并将其存储在首选项中,并且每次检查活动后退堆栈是否有任何内容。如果有,则删除(并从您的后退堆栈中删除)。如果您的活动后退堆栈不包含任何内容,则按照您的首选项进行操作。 - Vishal Mokal
@VishalMokal 感谢您的反馈。Activity的后退堆栈由片段管理器管理,这意味着有多种方法可以添加或删除片段到后退堆栈。此类解决方案也不适用于更大的应用程序。由于我还依赖于片段进行导航,因此更基本的解决方案更可取。 - Arun C
“我使用popBackStack来启用后退按钮行为”这句话是什么意思?如果你使用fragmentTransaction.begin().add(fragment).addToBackStack().commit()添加片段,Android系统不会自动管理后退按钮行为吗? - personne3000
请发布一些代码,展示如何添加和删除片段(例如,您是否有onBackPressed方法?) - Mimmo Grottoli
你好,能请您将您的代码放在这里吗? - Darshan Mistry
我很快会发布代码示例。 - Arun C
4个回答

12

尝试在您的根活动上使用alwaysRetainTaskState。 Android会自动清除Activity返回堆栈,因为它认为您已经很长时间没有使用过该应用程序,并且用户想从头再开始。

 <activity android:alwaysRetainTaskState="true"/>

这个设置会防止那种行为,这可能导致 Fragment Manager 继承该行为。


此标志仅适用于活动级别。 - Arun C
无效,当应用程序被杀死并使用通知打开时,返回堆栈仍将为空。 - Savita Sharma

6
在开发应用程序时,建议使用ADB测试活动和片段的还原/保存状态:
  1. 打开应用程序
  2. 在活动之间切换
  3. 按Home键
  4. ADB -> 停止应用程序
  5. 按下应用程序堆栈 (设备上的菜单按钮) 并恢复应用程序
这样可以调试保存/还原状态。
如果您的应用程序不太复杂,建议在活动中处理保存/还原状态。
private Fragment1 mFragment;

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

   if (savedState == null) {
       mFragment = new Fragment1();

       getFragmentManger().beginTransacation().add(mFragment, TAG).addToBackStack(TAG).commit();
   }
   else {
       mFragment = getFragmentMananager().findFragmentByTag(TAG);
   }
}

如果你有多个Fragments或者一个ViewPager或者嵌套的fragments,那么事情可能会变得非常复杂。我建议您重新启动整个应用程序:
@Override
protected void onCreate(Bundle savedState) {
   super.onCreate(savedState);

   if (savedState != null) {
      Intent intent = new Intent(ActivityMain.this, ActivityMain.class);
      intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
      startActivity(intent);

      return;
   }
}

如果您想处理每个保存/还原状态,请阅读这篇文章:http://www.androiddesignpatterns.com/2013/08/fragment-transaction-commit-state-loss.html

如果您需要处理每个保存的状态和恢复,可以参考这篇文章。


我同意,如果您的根活动是托管片段的活动,则第二个解决方案(重新启动活动)是一个快速的解决方法,谢谢。 - Marco C.

1

0

Fragment C在应用程序关闭后不应该被加载。您的应用程序中是否有Init Fragment?理想情况下,当您实现片段弹出时,应该有一个Init屏幕。如果应用程序因内存原因死亡或被杀死,则应从Fragment A(Init Fragment)开始启动应用程序。而不是从Fragment C开始。

如果您的问题需要此解决方案,则每当新片段出现在顶部时,您都必须持久保存每个片段。这意味着您正在将backstack持久保存在首选项或数据库中以实现此目的。


Super.onCreate 在活动重新创建时将加载最后一个片段。此外,数据丢失得到了管理。令人关注的是片段的顺序。 - Arun C
你会将 savedInstance 对象传递给 onCreate 函数吗? - user1649464
是的,我正在传递相同的内容。 - Arun C
如果片段C正在自动加载,则此信息将保存在实例中。 您应该使用onSaveInstanceState()和onRestoreInstanceState()。您可以在此处获取有关它的完整描述: http://developer.android.com/training/basics/activity-lifecycle/recreating.html当您的活动再次启动时,您应该覆盖onSaveInstanceState()并恢复它。 - user1649464

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