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

Posted

技术标签:

【中文标题】按HOME后重新启动应用程序时如何返回最新启动的活动?【英文标题】:How to return to the latest launched activity when re-launching application after pressing HOME? 【发布时间】:2011-09-14 07:10:15 【问题描述】:

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

然而,发生的事情是他再次获得了 Main 活动。我感觉 android 正在创建 MainActivity 的 another 实例并将其添加到该应用程序的堆栈中,而不是仅仅选择顶部的任何内容,因为如果我在重新启动应用程序后按 BACK,我进入游戏活动!并且每次调用Main.onCreate方法,而不是调用GameActivity.onResume。

我的AndroidManifest.xml 几乎是“赤裸裸的”:

<activity android:name="MainActivity" android:label="@string/app_name">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

<activity android:name="GameActivity" android:label="@string/app_name">
</activity>

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

这就是新活动的启动方式,也很简单:

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

理论上,这应该在 Android 中“开箱即用”,正如对一个非常相似的问题的回答所说:Maintaining standard application Activity back stack state in Android (using singleTask launch mode),但事实并非如此。

我一直在阅读和重新阅读有关 Activity 和 Task 和 Stacks 的文档,并浏览了 SO 中的所有相关答案,但我不明白为什么这么简单的设置不能按预期工作。

【问题讨论】:

App always starts fresh from root activity instead of resuming background state (Known Bug)的可能重复 【参考方案1】:

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

我喜欢Sachin's answer,但有时它会给我带来误报,我会在不应该完成活动时完成。我发现重现这种误报的可靠方法是:

    从主屏幕启动应用程序 新闻主页 再次从主屏幕启动应用程序 按“返回”返回主屏幕 从“最近的应用”返回应用

我开始寻找方法来检查我的任务的活动回栈并使用 ActivityManager 找到答案。这似乎可行,但this answer 指出了isTaskRoot 的存在,这是一种简单、优雅的检测方法,不会产生误报,不需要特殊许可,也不会使用docuemtation 所说的方法旨在用于调试和任务管理应用程序,并且不支持此类用途。

【讨论】:

【参考方案2】:
    @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... 
 

【讨论】:

还有另一个标志要检查:FLAG_ACTIVITY_RESET_TASK_IF_NEEDED。如果设置了该标志并且未设置 FLAG_ACTIVITY_BROUGHT_TO_FRONT,则您的应用程序将重新启动,但所有活动都已关闭(例如,通过在最后一个活动上按下后退按钮)。应用中的静态数据仍然存在于内存中。 这是某种奇迹吗?我将此代码仅放入 MainActivity 并且它运行良好。但我不明白它是如何工作的。谁能解释一下? @SachinGurnani 非常感谢,只需复制并粘贴就可以了,干杯:) 非常感谢@SachinGurnani 寻找与@sachin 完全相同的东西【参考方案3】:

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

LaunchActivity -> MainActivtiy -> SomeSubActivtiy

LaunchActivtiy 只验证一些参数并启动MainActivtiy。 事实证明,MainActivity 必须使用

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

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

【讨论】:

这看起来是一个糟糕的解决方案,但是......由于缺乏在清单中设置的标志,我敢说你是对的。 :'(【参考方案4】:

我了解您来自哪里,但我认为操作系统不想做出任何假设。另外还有一个问题是您的应用程序已被回收,因为内存需要其他东西。因此,它将从您的 MainActivity 重新开始。

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

希望这会有所帮助!

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

【讨论】:

不是保存内部状态的问题。回到应用程序时没有显示正确的 Activity 是一个问题。【参考方案5】:

哦,我想我找到了答案。

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

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

参考:App always starts fresh from root activity instead of resuming background state (Known Bug)

所以我手动关闭了手机中的应用程序,然后从主屏幕小部件重新启动它。然后打开GameActivity,然后按HOME。现在,当重新启动它时,GameActivity 仍然可见,并保持它的 UI 状态与我离开时一样。

而且我猜想在之前按下快捷键时创建一个新的 Activity 实例的原因是因为启动 Activity 时使用了不同的 Intent。

【讨论】:

看起来您找到了自己的方式来解释其他 2 人试图告诉您的相同答案... ;0) @bytebender 在我看来不是这样 救命稻草。这对我的测试来说是一个巨大的痛苦。 不错的发现!节省我一些时间【参考方案6】:

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

您看到这个是因为您的应用可能在退出时被操作系统杀死。你永远无法确定,所以如果你想要真正的使用持久性,即无论如何都回到上一个活动,你需要将你的状态写入持久存储。

【讨论】:

您说的是数据持久性,而我说的是“临时/瞬态活动堆栈”持久性,这是系统确实提供的一项功能,在操作系统可以终止任务之前。抱歉,如果我不够清楚,但我认为您在回答其他问题。 @sole:我想你可能误解了Android开发的一个核心概念。或者我在你的问题中遗漏了一些东西。活动堆栈由操作系统管理并与您的进程相关联。如果您通过回家或使用回来离开您的应用程序,操作系统有权终止您的应用程序,这不是暂时的。 应用程序还没有被杀死,实际上应用程序需要很长时间才能被杀死。我说的是按 HOME 并几乎立即返回(例如被电话打断时)。对于这些情况,操作系统会保留应用程序的活动堆栈 :-) @sole:你确定吗?对我的游戏来说,应用程序终止时间不到 50 毫秒,并且发生了很多,因为大多数手机都内存不足,并且需要一些内存,所以操作系统会终止它。 默认您的应用程序将恢复到最后一个活动,如果没有,那么您正在做一些“奇怪”的事情或您的应用程序被杀死。 是的,请看我自己的回答。该应用程序没有被杀死。相反,由于第一个实例是通过我的 IDE 创建的,因此创建了另一个 MainActivity 实例。

以上是关于按HOME后重新启动应用程序时如何返回最新启动的活动?的主要内容,如果未能解决你的问题,请参考以下文章

android 按home键返回到桌面后,再按桌面应用图标又重新打开该应用的解决方法

android 按home键返回到桌面后,再按桌面应用图标又重新打开该应用的解决方法

Android:按home后恢复应用程序时,应用程序始终从根Activity启动

重新启动应用程序时如何恢复导航控制器路径?

Home 按键行为

重新启动后恢复视图状态