了解 Android 带有启动画面的启动模式

Understanding Android Launch modes with splash screens

我有 3 个活动:Splash(启动器)、登录仪表板。当应用程序打开时,Splash 会等待一段时间然后开始登录,finishing 本身。然后用户可以从登录导航到仪表板。

我想在用户单击主页按钮或通过可浏览的 Intent 指向应用程序时维护应用程序的单个实例。以便用户返回到切换应用程序之前的位置。

以下是android:launchMode="standard"singleInstancePerTask的行为(红色方块是完成的活动)

singleTask 的行为类似于标准模式的附加 Web 意图,我可以向 Splash 添加逻辑,以便它中断处理并在它不是 root 时完成:

最后,如果我选择 singleInstance,会发生以下情况:

这似乎可行,但有些事情我不明白。 为什么第二个 Splash 忽略启动登录的 Intent activity?。逻辑告诉我应该启动登录 #2。

物质表现:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.test.testintentflags">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.TestIntentFLags">

        <activity
            android:name=".SplashActivity"
            android:exported="true" android:launchMode="singleInstance">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <intent-filter android:autoVerify="true">
                <action android:name="android.intent.action.VIEW" />

                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />

                <data
                    android:host="demo.intents.com"
                    android:scheme="https" />
            </intent-filter>
        </activity>
        <activity
            android:name=".DashboardActivity"
            android:exported="false" />
        <activity
            android:name=".LoginActivity"
            android:exported="false" />
    </application>

</manifest>

这里发生了很多事情,我会尝试解决这些问题:

首先,在这里使用 launchMode="singleInstance" 是有问题的,因为您还没有为您的任何活动声明任何 taskAffinity。所以你的 SplashActivity 和你的其他活动有相同的(默认)taskAffinity 这告诉 Android 所有这些活动都想 运行 在同一个任务中,这与你的启动冲突SplashActivity 的模式声明。这很糟糕,你不应该这样做。如果你真的想在单独的任务中有活动运行,你应该确保它们有不同的taskAffinity,以免造成混淆。

其次,您写道:

This seems to work, but there is something that I don't understand. Why is the second Splash ignoring the Intent to launch Login activity?. The logic tells me that a Login #2 should've launched.

这里发生的事情是这样的:当 SplashActivity 调用 startActivity() 启动 LoginActivity 时,使用的 Intent 包含 FLAG_ACTIVITY_NEW_TASK 集合(因为 SplashActivity 是用 launchMode="singleInstance" 声明的,因此它必须将其他活动启动到新任务中),因此 Android 查找以 LoginActivity 作为其根的现有任务 Activity .如果找不到,它会简单地启动 LoginActivity 的新实例到新任务中。但是,在这种情况下,它会找到一个(这是图表中的任务 #2),因此它只是将该任务带到前台 而不会启动 LoginActivity[=66 的新实例=].

这与当您有一个应用 运行 时发生的行为相同,然后按下主屏幕按钮,然后再次单击该应用的应用图标。在这种情况下,Android 不会启动应用根 Activity 的新实例,它只是查找以应用启动 Activity 作为根 Activity 的现有任务并将该任务以任何状态置于前台。

我给你的建议如下:

  • 摆脱使用特殊启动模式 singleInstancesingleTask
  • 创建一个新的 BridgeActivity,用作网络浏览器和您的应用程序之间的桥梁。此 Activity 应该具有浏览器 Intent<intent-filter>
  • BridgeActivity 应该检查它是否是其任务中的根 Activity。如果不是,这意味着它已经启动到一个已被带到前台的现有任务中,它可以在 onCreate().
  • 中安静地 finish()
  • 如果 BridgeActivity 检测到它是其任务的根,它可以启动 SplashActivity(确保设置 FLAG_ACTIVITY_NEW_TASK)以开始一个新任务(因为显然没有'已经是您应用程序的现有任务)
  • 应该声明
  • BridgeActivity,这样它就不会出现在任务堆栈历史记录或最近任务列表中(noHistory="true"excludeFromRecents="true"