从 Android 应用安装程序和主屏幕启动应用程序时的活动堆栈排序问题

Posted

技术标签:

【中文标题】从 Android 应用安装程序和主屏幕启动应用程序时的活动堆栈排序问题【英文标题】:Activity stack ordering problem when launching application from Android app installer and from Home screen 【发布时间】:2011-09-15 10:26:30 【问题描述】:

仅出于测试目的,我允许通过 URL 下载和安装我的应用 APK。在手机上下载后,可以使用 android 应用安装程序启动它,用户可以选择将其安装到他们的设备上然后运行。

考虑我们是否以上述方式下载并运行应用程序。我的应用程序中的主/启动器活动是登录页面 (Activity A)。一旦用户通过身份验证,他们就会被带到应用程序的主要区域,例如。 Activity B。所以现在这个任务的当前活动栈是A > B

然后我按下手机上的主页按钮,然后进入 Android 主屏幕。我通过菜单中的图标重新启动我的应用程序,我被带到Activity A,而不是Activity B。要么活动堆栈现在是A > B > A,要么现在有两个单独的任务,活动堆栈分别为A > BA。我想要的是在我重新启动应用程序时回到Activity B。在这种状态下按回将带我回到Activity B

这种不良行为只有在我首先通过安装程序打开应用程序时才会发生,而不是在我通过主屏幕/菜单打开应用程序时发生。

我研究了每个机制是如何启动活动的。当我们使用应用安装程序时,我们会看到以下日志:

INFO/ActivityManager(XXXX): Starting activity: Intent  dat=file:///mnt/sdcard/download/[my app].apk cmp=com.android.packageinstaller/.InstallAppProgress (has extras) 
INFO/ActivityManager(XXXX): Starting activity: Intent  act=android.intent.action.MAIN flg=0x10000000 cmp=[my package]/[Activity A] 

通过启动器/主屏幕:

INFO/ActivityManager(XXXX): Starting activity: Intent  act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=[my package]/[Activity A] 

使用安装程序启动时,我们看到它使用标志0x10000000,但启动启动器时我们看到它使用0x10200000。它还使用了一个意图类别。

从docs 我们看到标志是:

public static final int FLAG_ACTIVITY_NEW_TASK
Constant Value: 268435456 (0x10000000)

public static final int FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
Constant Value: 2097152 (0x00200000)

标志FLAG_ACTIVITY_RESET_TASK_IF_NEEDED(在从启动器启动应用程序时使用)似乎通常会阻止创建新任务(如果已存在),并将恢复上次使用的活动。这是期望的行为。为什么它在这种情况下不起作用?我可以做些什么来确保我的应用程序始终将我返回到上一个 Activity,无论它是否是通过应用程序安装程序/启动器启动的?

如果我使用singleTask,每当我运行应用程序时,它总是会带我回到主要活动 (Activity A)(这也是不可取的)。

这是我发现有人遇到类似问题的问题(没有公认的答案):App loses its ability to remember its stack when launched from another application

编辑:在我们的启动器活动的onCreate() 中检查标志FLAG_ACTIVITY_BROUGHT_TO_FRONT(如果已设置,则完成)似乎可以解决主要症状,但显然根本问题仍然存在。有更完整的修复方法吗?

EDIT2:当您从 Android Market 下载/运行应用程序时,会出现相同的结果,因此上述某些详细信息可能不相关。

【问题讨论】:

检查 FLAG_ACTIVITY_BROUGHT_TO_FRONT 效果很好。您可以将其发布为答案吗? 另一个可重现的场景:从市场应用启动应用 和***.com/a/16447508/769265的情况基本一样,2019年还在破! 【参考方案1】:

添加了antonyt提供的答案:

@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...

【讨论】:

thnx 代码,我还在这里学习了一种编写 if 条件的新方法,但是如果在某些情况下,即使应用程序启动器总是使用 FLAG_ACTIVITY_BROUGHT_TO_FRONT 标记启动,您也应该添加 还没有在任务中,因此会完全锁定它们,因为它会调用 finish() 并且堆栈中没有任何东西可以返回。 As there it is written in answer from where this answer is taken。进行此检查时要记住这一点似乎很重要。 @VishwasSharma - 您提出的问题听起来像是 Android 平台错误。 Android 怎么会同意锁定状态? 锁定的情况将由放置在上面代码中的检查引入(虽然不太可能发生),而不是由android,如果你知道应用程序是如何启动的,你应该已经要知道,如果您从菜单启动应用程序,它会以不同的意图标志启动,如果您从启动器菜单启动它,那么它会设置不同的标志(这就是我们需要此检查的原因),如果您从 Eclipse 启动,它会启动不同。我想说的是,该应用程序是使用与您启动应用程序的位置相对应的标志启动的。 所以,我不认为这是android平台的错误,但他们需要在制作应用程序启动平台时考虑这一点。虽然,这可能是 eclipse 应用程序启动机制中的一个错误,这在 here 中进行了解释 我遇到了完全相同的问题。我尝试了这个解决方案,但它对我不起作用。通过菜单启动时的值:Intent flg=0x10104000 cmp=.activities.Login bnds=[214,520][429,721] 标志:269500416 通过普通应用程序图标启动时,不会创建登录活动。任何帮助将不胜感激。【参考方案2】:

您的问题可能源于应用程序安装程序不使用 LAUNCHER 类别,启动器也是如此。

此错误已在其他地方记录:

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

【讨论】:

【参考方案3】:

我认为根本问题是启动器和安装程序之间使用的Intents 不同。只要您获得不同的 Intent 标志,您将获得不同的启动行为。您可以使用启动模式,您可能能够获得一致的结果,但从根本上说,这些不同的 Intent 会产生不同的结果。

您的修复(或类似this)可能是您最好的选择。

【讨论】:

这似乎是许多应用程序认为不受欢迎的基本问题 - 事实上,我已经看到 Android Facebook 应用程序表现出这种行为 - 因此,上述解决方法(或类似的)全部是非常令人失望的我们可以做到。 它可以被认为是一种行为缺陷:另一方面,它确实允许您区分安装程序启动和应用程序图标启动,您可以使用它们来启动 Welcome仅当有人单击安装程序运行按钮时才显示的屏幕。现在我想起来了,我实际上可能会使用它:) @Femi 但是,请记住,并非每个人都会通过“安装并运行”选项第一次启动该应用程序,当他们开始使用它时,他们可能仍会感激问候。 :) 非常正确:我的应用程序中已经有逻辑可以检查第一次运行,这只是一个钩子。 我试图检测是否在用于启动活动的意图中设置了类别(它通常不是由安装程序设置,只有启动器) - 如果它丢失,我添加类别和标志,然后使用此修改后的意图重新启动 (startActivity()/finish())。即使现在的意图似乎匹配,不良行为仍然会发生。你对此有什么想法吗?

以上是关于从 Android 应用安装程序和主屏幕启动应用程序时的活动堆栈排序问题的主要内容,如果未能解决你的问题,请参考以下文章

从原生 iOS 和 Android 应用程序启动到 OutSystem 移动应用程序的特定屏幕

当应用程序从商店更新或首次安装在 Android 中时,如何调用特定函数?

Android - 检测应用程序从家庭或历史启动

在菜单栏和主屏幕中为 Activity 定义不同的标题

应用程序已安装,但图标未出现在启动器屏幕或应用程序列表中

如何删除状态栏和主屏幕之间的分隔线/阴影?