当从另一个应用程序启动时,应用程序失去了记住其堆栈的能力

Posted

技术标签:

【中文标题】当从另一个应用程序启动时,应用程序失去了记住其堆栈的能力【英文标题】:App loses its ability to remember its stack when launched from another application 【发布时间】:2011-07-16 04:32:01 【问题描述】:

现在我已经对此进行了更多研究,我正在重写它以使其更清晰。如果您正在寻找更多信息,可以在旧版本中找到一些信息。

发生了什么:

(这是指没有设置任何launchMode的应用程序 设置,所以使用默认值)

    您从市场或安装程序启动应用程序。这 启动应用程序的根/主要活动 FLAG_ACTIVITY_NEW_TASK 标志并且没有类别。现在的 应用程序堆栈是 [ A ]

    然后您继续进行应用程序中的下一个活动。现在 此任务中的堆栈为 [ A > B ]

    然后您按下主页键,然后重新启动相同的应用程序 通过在主屏幕或应用托盘中按下它的图标。

    此时预期活动 B 将显示,因为 那是你停下来的地方。但是显示了 A 并且任务堆栈是 [ A > B > A ] A 的第二个实例是用 以下标志:FLAG_ACTIVITY_NEW_TASK, FLAG_ACTIVITY_RESET_IF_NEEDED 和 FLAG_ACTIVITY_BROUGHT_TO_FRONT。它 也有 android.intent.category.LAUNCHER 类别。

此时,如果你按下返回键,它会将你返回到 B,因为它 是你离开的时候。

查看文档似乎 FLAG_ACTIVITY_BROUGHT_TO_FRONT 应该只为那些活动设置 使用 singleTask 或 singleTop 启动模式。然而,这 应用程序没有设置任何启动模式,因此正在使用 默认标准启动模式。

我认为在这种情况下不会发生这种情况?

我还应该注意,一旦它进入这种奇怪的状态,那么每次从主屏幕或应用程序托盘启动应用程序时都会发生这种情况。如果任务完成(重新启动 电话,强制停止应用程序,或一直回击 stack) 将解决此问题,并且不会再错误地启动它。 仅当您从安装程序或市场启动应用程序并且 然后尝试从启动器启动它。

总之,为什么会发生这种情况?有什么办法可以预防吗?

【问题讨论】:

你很细心!同样的事情开始发生在我的应用程序上,我真的不知道该怎么处理它!特别是当我从 Eclipse 中安装 apk 时,它工作正常。 Activity stack ordering problem when launching application from Android app installer and from Home screen的可能重复 与***.com/a/16447508/769265 相同的问题,并在 2019 年仍然损坏! 【参考方案1】:

这是我迄今为止想出的一种解决方法。我见过的其他一些解决方法涉及查看当前正在运行的任务。但是,我真的不想为了解决问题而向用户请求另一个权限 (GET_TASKS)。

如果您发现其中有任何漏洞,请告诉我。

在 main/root Activity 的 onCreate 方法中,检查 Intent 是否有 FLAG_ACTIVITY_BROUGHT_TO_FRONT 设置,如果是,则调用 finish()。这 然后将 A 的额外实例从堆栈中弹出 [ A > B > A ] 变为 [ A > B ] 从用户的角度来看,它启动到 他们期待的活动。

到目前为止,它似乎在我所有的测试中都有效。我唯一担心的是,如果 在某些奇怪的情况下,某人的启动器总是会标记一个 使用 FLAG_ACTIVITY_BROUGHT_TO_FRONT 启动,即使应用程序不是 已经在一项任务中,因此会将它们完全锁定 因为它会调用 finish() 并且堆栈中没有任何内容 返回。

--

根据 cmets 的要求,您可以如何检查意图是否为特定标志:

int flags = intent.getFlags();
boolean hasFlag = flags & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT == Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT;

--

另外我应该注意,我仍然会看到这个问题有时会在修复后出现。这似乎不是一个完美的解决方案。

【讨论】:

@GSree,是的,因为我自己处理配置更改。我不确定如果我关闭它会发生什么。不过,我认为这会很好。这个问题似乎与它的启动方式有关。 如何针对某些标志测试 Intent? IE。你怎么知道 Intent 是用 FLAG_ACTIVITY_BROUGHT_TO_FRONT 调用的?【参考方案2】:

重写 onConfigurationChanged() 应该可以帮助您保持状态。

http://developer.android.com/reference/android/app/Activity.html

配置更改

如果设备的配置(由 Resources.Configuration 类定义)发生更改,则显示用户界面的任何内容都需要更新以匹配该配置。因为 Activity 是与用户交互的主要机制,所以它包括对处理配置更改的特殊支持。

除非您另外指定,否则配置更改(例如屏幕方向、语言、输入设备等的更改)将导致您当前的活动被破坏,并通过 onPause() 的正常活动生命周期过程,onStop( ) 和 onDestroy() 视情况而定。如果 Activity 位于前台或用户可见,则在该实例中调用 onDestroy() 后,将创建该 Activity 的新实例,使用前一个实例从 onSaveInstanceState(Bundle) 生成的 saveInstanceState。

这样做是因为任何应用程序资源(包括布局文件)都可以根据任何配置值进行更改。因此,处理配置更改的唯一安全方法是重新检索所有资源,包括布局、可绘制对象和字符串。因为 Activity 必须已经知道如何保存其状态并从该状态重新创建自己,所以这是一种使用新配置重新启动 Activity 自身的便捷方式。

在某些特殊情况下,您可能希望根据一种或多种类型的配置更改绕过重新启动活动。这是通过清单中的 android:configChanges 属性完成的。对于您说在那里处理的任何类型的配置更改,您将收到对当前活动的 onConfigurationChanged(Configuration) 方法的调用,而不是重新启动。但是,如果配置更改涉及您未处理的任何内容,则活动仍将重新启动,并且不会调用 onConfigurationChanged(Configuration)。"

【讨论】:

感谢您的回复。我实际上已经为我的所有活动覆盖了 configurationChanges,但我认为这并不真正适用于问题。以前的活动甚至再也不会被调用,调用直接转到根活动 A。 @littleFluffyKitty 我也有类似的问题,我使用了一个单例类对象来存储对象的最后一个活动 但是您不会丢失活动的状态,因为它们的 onSavedInstanceState 值会被清除吗? @littleFluffyKitty 好吧......对我来说,这个活动有逻辑点,我可以触发更新单例类。例如。媒体文件播放结束...实现了 MediaPlayer.OnCompletionListener 并更新了我的单例。不确定您的应用程序是否有可以控制的逻辑点。

以上是关于当从另一个应用程序启动时,应用程序失去了记住其堆栈的能力的主要内容,如果未能解决你的问题,请参考以下文章

当从另一个 ViewController 类调用方法时,Xcode 找到一个 nil 变量,其中不应该是任何变量

仅当从另一个查询中选择时,SQL Select 语句才突然检索错误值

当从另一个 ObservedObject 链接到 Published 属性时,视图不会对更改做出反应

当从另一个控制器(弹出窗口)访问 UILabel(作为一个插座)时,它仍然为零

初始 CoreData 对象的类型错误。

从另一个用户记录堆栈跟踪错误:不幸的是,应用程序已停止