熟悉的场景:我有一个 Main 活动,当按下按钮时会启动 Game 活动。如果用户按下HOME,然后再次启动我的应用程序,则应该显示 Game 活动,这是他在使用该应用程序时最后所做的事情。
然而,相反的是他再次获得 Main 活动。我觉得Android正在创建另一个 MainActivity实例,并将其添加到该应用程序的堆栈中,而不是只选择顶部的任何内容,因为如果我在重新启动应用程序后按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);
从理论上讲,这应该只适用于“开箱即用”,因为对于一个非常相似的问题的回答是:Maintaining standard application Activity back stack state in Android (using singleTask launch mode),但事实并非如此。
我一直在阅读和重新阅读有关活动和任务和堆栈的文档,并在SO中浏览所有相关答案,但我无法理解为什么这么简单的设置不能按预期工作。
答案 0 :(得分:28)
@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...
}
答案 1 :(得分:18)
哦,我想我找到了答案。
因为我是使用IntelliJ启动应用程序,所以它似乎以不同于用户的方式启动应用程序,单击主屏幕小部件,将启动。在另一个SO问题的答案中解释了这一点:
这是因为用于启动应用程序的意图不同。 Eclipse使用没有操作且没有类别的intent启动应用程序。 Launcher使用android.intent.action.MAIN动作和android.intent.category.LAUNCHER类别的intent启动应用程序。安装程序使用android.intent.action.MAIN操作启动应用程序,没有类别。
参考:App always starts fresh from root activity instead of resuming background state (Known Bug)
所以我手动杀死手机中的应用程序,然后从主屏幕小部件重新启动它。然后打开GameActivity,按下HOME。现在,重新启动时,GameActivity仍然可见,并保持其状态,就像我离开时一样。
我想之前按下快捷键时创建活动的新实例的原因是由于使用了不同的Intent来启动活动。
答案 2 :(得分:2)
最简单的解决方案是在onPause期间写出首选项或将状态序列化为持久文件,然后在主入口点Activity中的onResume期间读取此文件。此活动将重建应用程序状态并重新启动正确的活动。
你看到了这个,因为你的应用可能在退出时被操作系统杀死。你永远不知道如果你想要真正持久的使用,即回到上一个活动,无论如何,你需要将你的状态写入持久存储。
答案 3 :(得分:2)
我强烈建议您使用isTaskRoot检查是否应该完成活动,而不是FLAG_ACTIVITY_BROUGHT_TO_FRONT标志。
我喜欢Sachin's answer,但有时它给了我假阳性,我会在不应该的时候完成活动。我发现重现这种假阳性的可靠方法是:
我开始寻找方法来检查我的任务的活动backstack并使用ActivityManager找到答案。这似乎可行,但this answer指出了isTaskRoot的存在,这是一种简单,优雅的方法来检测这种情况,不会产生误报,不需要特别许可,不使用docuemtation所说的用于调试和任务管理应用程序的方法,以及不支持此类用法的方法。
答案 4 :(得分:1)
我知道你来自哪里,但我认为操作系统不想做任何假设。此外,您的应用程序已被回收,因为内存需要其他内容。在那个原因中,它将从您的MainActivity开始。
根据游戏的复杂程度,您可以在SharedPreferences中保存状态,也可以在活动的onPause()方法中保存SqlLite数据库。然后onResume()您可以将用户恢复到最后一个状态,其中可能包括“重新启动”您的GameActivity。
希望这有帮助!
编辑:我所说的是,作为开发人员,我们有责任向用户显示/保证在返回应用程序时显示正确的活动。你的应用程序的内存总是有可能被回收,然后android将重新启动你用MAIN和LAUNCHER意图标记的活动。通过保存状态(活动ID),您可以将它们从主...重定向到该活动
答案 5 :(得分:1)
我在我的应用程序中使用以下活动堆栈来解决问题:
LaunchActivity - &gt; MainActivtiy - &gt; SomeSubActivtiy
LaunchActivtiy 仅验证某些参数并启动 MainActivtiy 。 事实证明,必须使用
启动 MainActivityintent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
MainActivity 上的标记组合可以提供所需的行为。