应用程序重新启动而不是恢复

Gra*_*eme 179 android android-lifecycle

希望有人可以帮助我弄清楚,如果不是解决方案,至少可以解释一个行为.

问题:

在某些设备上,按启动器图标会导致当前任务恢复,而在其他设备上则会导致初始启动意图被触发(有效地重新启动应用程序).为什么会这样?

细节:

当您按下"启动器图标"时,应用程序会正常启动 - 也就是说,我认为,会Activity使用操作android.intent.action.MAIN和类别以您的第一个名称启动一个Intent android.intent.category.LAUNCHER.但情况并非总是如此:

在大多数设备上,如果在应用程序运行后按下启动器图标,则恢复该进程中当前运行的活动(不是初始Activity).它的恢复方式与从OS菜单中的"Recent Tasks"中选择它的方式相同.这是我想要在所有设备上执行的操作.

但是,在选定的其他设备上会出现不同的行为

  • 在摩托罗拉Xoom上,当您按下启动器图标时,无论当前运行的是什么,应用程序都将始终启动初始启动Activity.我假设启动器图标总是启动"启动器"意图.

  • 在Samsung Tab 2上,当您按下启动器图标时,如果您刚刚安装了应用程序,它将始终启动初始设置Activity(与Xoom相同) - 但是,在安装后重新启动设备后,启动器图标将改为恢复应用程序.我假设这些设备在设备启动时将"已安装的应用程序"添加到查找表中,这允许启动器图标正确地恢复正在运行的任务?

我读过许多回答听起来类似我的问题,但简单地添加android:alwaysRetainTaskState="true"或使用launchMode="singleTop"Activity不是答案.

编辑:

在最近发布此应用程序后,我们发现在首次重新启动后,所有设备上都会出现此行为.这看起来很疯狂,但通过重启过程,我实际上无法找到出错的地方.

sta*_*ej2 215

您遇到的行为是由自API 1以来某些Android启动器中存在的问题引起的.您可以在此处找到有关错误的详细信息以及可能的解决方案:https://code.google.com/p/android/issues/详情?id = 2373.

这是三星设备以及使用自定义启动器/皮肤的其他制造商的相对常见问题.我还没有看到Android Android启动器出现问题.

基本上,应用程序实际上并没有完全重新启动,但是当启动程序恢复应用程序时,您的启动活动正在启动并添加到活动堆栈的顶部.您可以通过在恢复应用程序时单击后退按钮来确认是这种情况,并显示启动活动.然后,您应该被带到您希望在恢复应用程序时显示的活动.

我选择实现解决此问题的解决方法是检查启动初始Activity的intent中的Intent.CATEGORY_LAUNCHER类和Intent.ACTION_MAIN操作.如果存在这两个标志并且Activity不在任务的根目录(意味着应用程序已在运行),那么我在初始Activity上调用finish().这个确切的解决方案可能不适合你,但类似的东西应该.

这是我在初始/启动活动的onCreate()中所做的事情:

    if (!isTaskRoot()
            && getIntent().hasCategory(Intent.CATEGORY_LAUNCHER)
            && getIntent().getAction() != null
            && getIntent().getAction().equals(Intent.ACTION_MAIN)) {

        finish();
        return;
    }
Run Code Online (Sandbox Code Playgroud)

  • 到目前为止,这对我有用,迄今为止没有任何不良副作用.基于逻辑假设,我认为没有理由说它无效. (4认同)
  • 我认为这是处理此错误的正确方法。为我工作。 (3认同)
  • 在大约8种不同的设备上为我完成了工作。非常感谢! (3认同)
  • WOOOOOW解决了我的问题,我过去两个小时一直在寻找解决方案 (3认同)
  • 天才..这解决了我的问题...谢谢老兄 (3认同)
  • 该解决方案挽救了我的生命。谢啦! (2认同)
  • 谢谢@ starkej2。像魅力一样工作。 (2认同)

Ric*_*mer 47

这个问题在2016年仍然具有现实意义.今天,QA测试人员报告了一个应用程序重启而不是 Android M中的库存启动器恢复.

实际上,系统正在将已启动的活动添加到当前任务堆栈中,但对用户来说似乎已经发生重启并且他们已经丢失了工作.顺序是:

  1. 从Play商店下载(或侧载apk)
  2. 从Play商店对话框启动应用程序:活动A出现[任务堆栈:A]
  3. 导航到活动B [任务堆栈:A - > B]
  4. 按"主页"按钮
  5. 从app抽屉启动应用程序:活动A出现![任务堆栈:A - > B - > A](用户可以按'返回'按钮从此处进入活动'B')

注意:此问题不适用于通过ADB部署的调试APK,仅适用于从Play商店下载或侧载的APK.在后一种情况下,步骤5中的启动意图包含标志Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT,但不包含在调试情况中.一旦应用程序从启动器冷启动,问题就消失了.我的怀疑是,任务被种植了一个格式错误(更准确,非标准)的Intent,它会阻止正确的启动行为,直到完全清除任务.

我尝试了各种活动启动模式,但这些设置偏离了用户期望的标准行为:在活动B处恢复任务.请参阅页面底部的任务和后台堆栈指南中的预期行为的以下定义在'开始任务'下:

这种意图过滤器会导致活动的图标和标签显示在应用程序启动器中,从而为用户提供启动活动并在启动后随时返回创建的任务的方法.

我发现这个答案是相关的,并将以下内容插入到我的根活动(A)的'onCreate'方法中,以便在用户打开应用程序时适当地恢复.

                    /**
     * Ensure the application resumes whatever task the user was performing the last time
     * they opened the app from the launcher. It would be preferable to configure this
     * behavior in  AndroidMananifest.xml activity settings, but those settings cause drastic
     * undesirable changes to the way the app opens: singleTask closes ALL other activities
     * in the task every time and alwaysRetainTaskState doesn't cover this case, incredibly.
     *
     * The problem happens when the user first installs and opens the app from
     * the play store or sideloaded apk (not via ADB). On this first run, if the user opens
     * activity B from activity A, presses 'home' and then navigates back to the app via the
     * launcher, they'd expect to see activity B. Instead they're shown activity A.
     *
     * The best solution is to close this activity if it isn't the task root.
     *
     */

    if (!isTaskRoot()) {
        finish();
        return;
    }
Run Code Online (Sandbox Code Playgroud)

更新:将此解决方案从解析意图标志转移到查询活动是否直接位于任务的根目录.意图标志难以预测和测试,以打开MAIN活动的所有不同方式(从家里启动,从"向上"按钮启动,从Play商店启动等)

  • 注意:您可以通过使用应用程序的Google Play页面中的"打开",在最初清除它后(通过"冷启动")再次重现该问题,*即使您通过Android Studio*安装了APK .我发现这对验证修复工作非常有用. (11认同)
  • "一旦应用程序从发射器冷启动,问题就会消失." 这是最奇怪的部分,我也观察到它 - 在第一次启动后杀死应用程序,它开始正常表现.这么奇怪的错误.感谢您彻底分析它并为解决方案. (4认同)
  • 许多应用程序都会发生这种情况。Google相册是我测试过的主要照片。 (2认同)

Gra*_*eme 18

啊哈!(tldr;见底部粗体的陈述)

我发现了问题......我想.

所以,我将从一个假设开始.当您按下启动器时,它会启动默认值,Activity或者,如果上一次Task启动启动,它会将它带到前面.换一种说法-如果在您的导航任何阶段,您创建一个新的Taskfinish旧的,发射器现在将不再恢复您的应用程序.

如果这个假设是真的,我很确定这应该是一个bug,因为每个Task都在同一个进程中并且与第一个创建的候选简历一样有效吗?

我的问题是通过从以下几个删除这些标志来解决的Intents:

i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK );
Run Code Online (Sandbox Code Playgroud)

虽然FLAG_ACTIVITY_NEW_TASK创造一个新的很明显Task,但我并不理解上述假设是有效的.我确实认为这是一个罪魁祸首,并将其删除进行测试,我仍然遇到问题所以我解雇了它.但是,我仍然有以下条件:

i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
Run Code Online (Sandbox Code Playgroud)

我的启动画面Activity使用上面的标志在我的应用程序中启动了"main" .毕竟,如果我"重新启动"我的应用程序并且Activity仍在运行,我宁愿保留它的状态信息.

你会在文档中注意到它没有提到开始一个新的Task:

如果已设置,并且正在启动的活动已在当前任务中运行,则不会启动该活动的新实例,而是将关闭其上的所有其他活动,并将此Intent传递给(现在开启) top)旧活动作为新的意图.

例如,考虑一个由活动组成的任务:A,B,C,D.如果D调用带有解析为活动B组件的Intent的startActivity(),则C和D将完成,B接收给定的Intent ,导致堆栈现在是:A,B.

上面示例中当前运行的活动B实例将在其onNewIntent()方法中接收您从此处开始的新意图,或者本身已完成并使用新意图重新启动.如果它已将其启动模式声明为"多个"(默认值)并且您没有在同一意图中设置FLAG_ACTIVITY_SINGLE_TOP,那么它将被完成并重新创建; 对于所有其他启动模式或如果设置了FLAG_ACTIVITY_SINGLE_TOP,则此Intent将被传递到当前实例的onNewIntent().

此启动模式也可以与FLAG_ACTIVITY_NEW_TASK结合使用:如果用于启动任务的根活动,它将把该任务的任何当前运行的实例带到前台,然后将其清除到其根状态.这在从通知管理器启动活动时尤其有用.

所以,我有如下所述的情况:

  • A推出BFLAG_ACTIVITY_CLEAR_TOP,A结束.
  • B希望重新启动服务,以便向A具有服务重启逻辑和UI(无标志)的用户发送.
  • AB使用FLAG_ACTIVITY_CLEAR_TOP 启动,A完成.

在此阶段,第二个FLAG_ACTIVITY_CLEAR_TOP标志正在重新启动B,它位于任务堆栈中.我假设这必须摧毁Task并开始一个新的,导致我的问题,如果你问我这是一个非常困难的情况!

所以,如果我所有的假设都是正确的:

  • Launcher只恢复最初创建的任务
  • FLAG_ACTIVITY_CLEAR_TOP将,如果它重新启动唯一剩余Activity,也将重新创建一个新的Task

  • 我意识到这并不意味着 - 但通过反复试验,我的实例就是这种情况.删除这些标志可以解决问题. (2认同)

Ali*_*Ali 8

我在三星设备上遇到了同样的问题.经过大量的搜索,这些答案都不适合我.我发现在AndroidManifest.xml文件中,launchMode设置为singleInstance(android:launchMode="singleInstance").删除launchMode属性修复了我的问题.


小智 6

在我的 Cat s60 上,我在开发者选项中启用了“不保留活动”,再次禁用此功能可以让我在不丢失应用程序状态的情况下切换应用程序......


归档时间:

查看次数:

63355 次

最近记录:

7 年,3 月 前