按HOME后重新启动应用程序时如何返回最新启动的活动?

熟悉的场景:我有一个Main活动,在按下按钮时启动游戏活动。 如果用户按下HOME,然后再次启动我的应用程序,则应该显示Game活动,这是他在使用该应用程序时最后所做的事情。

然而,相反的是他再次获得Main活动。 我觉得Android正在创建另一个 MainActivity实例并将其添加到该应用程序的堆栈中,而不是只选择顶部的任何内容,因为如果我在重新启动应用程序后按BACK,我会进入Game活动! 并且每次调用Main.onCreate方法,而不是调用GameActivity.onResume。

我的AndroidManifest.xml几乎是“骨头”:

         

如你所见,没有什么太花哨的。

这就是新活动的推出方式,也非常简单:

 Intent intent = new Intent(this, GameActivity.class); startActivity(intent); 

从理论上讲,这应该在Android中起到“开箱即用”的作用,因为对一个非常相似的问题的回答是: 在Android中维护标准应用程序活动后备堆栈状态(使用singleTask启动模式) ,但事实并非如此。

我一直在阅读和重读有关活动和任务和堆栈的文档,并在SO中浏览所有相关的答案,但我不明白为什么这么简单的设置不能按预期工作。

  @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) != 0) { // Activity was brought to front and not created, // Thus finishing this will get us to the last viewed activity finish(); return; } // Regular activity creation code... } 

哦,我想我find了答案。

因为我是使用IntelliJ启动应用程序,所以它似乎以不同于用户的方式启动应用程序,单击主屏幕小部件,将启动。 在另一个SO问题的答案中解释了这一点:

这是因为用于启动应用程序的意图不同。 Eclipse使用没有操作且没有类别的intent启动应用程序。 Launcher使用android.intent.action.MAIN动作和android.intent.category.LAUNCHER类别的intent启动应用程序。 安装程序使用android.intent.action.MAIN操作启动应用程序,没有类别。

参考: 应用程序始终从根活动开始新鲜而不是恢复背景状态(已知错误)

所以我手动杀死了手机中的应用程序,并从主屏幕小部件再次重新启动它。 然后打开GameActivity,按下HOME。 现在,重新启动时,GameActivity仍然可见,并保持其状态,就像我离开时一样。

我猜想之前按下快捷键时创建活动的新实例的原因是由于使用了不同的Intent来启动活动。

最简单的解决方案是在onPause期间写出首选项或将状态序列化为持久文件,然后在主入口点Activity中的onResume期间读取此文件。 此活动将重建应用程序状态并重新启动正确的活动。

你看到这个是因为你的app 可能会在退出时被操作系统杀死。 你永远不知道如果你想要真正持久的使用,即无论如何回到最后一个活动,你需要将你的状态写入持久存储。

我强烈建议使用isTaskRoot检查是否应该完成活动而不是FLAG_ACTIVITY_BROUGHT_TO_FRONT标志。

我喜欢Sachin的答案 ,但有时它会给我误报,我会在不应该的时候完成这项活动。 我发现重现这种假阳性的可靠方法是:

  1. 从主屏幕启动应用程序
  2. 按回家
  3. 再次从主屏幕启动应用程序
  4. 按“返回”返回主屏幕
  5. 从“最近的应用”返回应用

我开始寻找方法来检查我的任务的活动backstack并使用ActivityManagerfind答案。 这似乎可以起作用,但是这个答案指出isTaskRoot的存在,这是一种简单,优雅的方法来检测它,不会产生误报,不需要特殊许可,也不使用docuemtation方法say适用于调试和任务管理应用程序,并且不支持此类用途。

我知道你来自哪里,但我认为操作系统不想做任何假设。 此外,您的应用程序已被回收,因为内存需要其他内容。 在那个原因中,它将从您的MainActivity开始。

根据游戏的复杂程度,您可以在SharedPreferences中保存状态,也可以在活动的onPause()方法中保存SqlLite数据库。 然后onResume()您可以将用户恢复到最后一个状态,其中可能包括“重新启动”您的GameActivity。

希望这可以帮助!

编辑:我所说的是,作为开发人员,我们有责任向用户显示/保证在返回应用程序时显示正确的活动。 你的应用程序的内存总是有可能被回收,然后android将重新启动你用MAIN和LAUNCHER意图标记的活动。 通过保存状态(活动ID),您可以将它们从主要重定向到该活动…

我在我的应用程序中使用以下活动堆栈来解决问题:

LaunchActivity – > MainActivtiy – > SomeSubActivtiy

LaunchActivtiy仅validation某些参数并启动MainActivtiy 。 事实certificate,必须启动MainActivity

 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); 

MainActivity上的标志组合提供了所需的行为。