应用程序快捷方式只能使用一次,之后才恢复应用程序

App Shortcut only works once, just resumes the app after that

我有一个动态应用程序快捷方式,如下所示

ShortcutInfo composeShortcut = new ShortcutInfo.Builder(App.getInstance(),
                                                                           getString(R.string.compose_shortcut_id))
                    .setShortLabel(getString(R.string.compose_app_shortcut_short_label))
                    .setLongLabel(getString(R.string.compose_app_shortcut_long_label))
                    .setDisabledMessage(getString(R.string.compose_app_shortcut_disabled_message))
                    .setIcon(Icon.createWithResource(App.getInstance(), R.drawable.compose_icon))
                    .setIntent(new Intent(context, ComposeActivity.class))
                                              .setAction(Intent.ACTION_DEFAULT)
                                              .setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP))
                    .build();
            shortcutManager.setDynamicShortcuts(Arrays.asList(composeShortcut));

我第一次点击这个快捷方式时,它打开 ComposeActivity 很好,但之后就不行了,我必须终止该应用程序,然后它再次运行一次。

所需流程 - 每当我单击应用程序快捷方式时,ComposeActivity 应该打开。如果应用程序已经是 运行,那么仅当当前 activity 还不是 ComposeActivity 时,ComposeActivity 才应该在当前 activity 之上打开。

当前流程 - 我第一次按下应用程序快捷方式时,Compose activity 可以正常打开,但之后就不行了。应用程序仅在此之后恢复。我必须终止该应用程序,然后再次单击它的快捷方式以打开 ComposeActivity.

更多信息 - AndroidManifest 中的 Compose Activity 是这样定义的:

...
<activity 
android:name=".shared.publish.compose.view.activity.ComposeActivity"
android:screenOrientation="portrait"
android:theme="@style/compose_theme"
android:windowSoftInputMode="stateVisible|adjustResize"/>

<activity
    android:name=".shared.activity.SplashScreenActivity"
    android:label="@string/app_name"
    android:screenOrientation="portrait"
    android:theme="@style/splash_screen_theme">
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>
</activity>
...

如我所料,问题是由于您使用了 ShortcutManager。这是 documentation 中的重要部分:

Only main activities—activities that handle the MAIN action and the LAUNCHER category—can have shortcuts. If an app has multiple main activities, these activities have different sets of shortcuts.

您的快捷方式 Intent 看起来像一个启动器 Intent。当用户点击一个应用程序图标时,这会生成一个启动器 Intent(ACTION=MAIN 和 CATEGORY=LAUNCHER)。 Android 然后查看是否已经有一个活动任务将此启动器 Activity 作为根 Activity。如果它找到一个,它所做的就是将该任务带到前台。如果找不到,它会创建一个新任务并将启动器 Activity 作为根 Activity 启动到新任务中。这正是您所看到的行为,也正是用户所期望的。如果您正在使用 Gmail 或其他一些应用程序,然后接听电话(将该应用程序推到后台),那么当您 return 到主屏幕并再次单击该应用程序图标时,您希望返回到该应用程序与您离开时完全一样。这是标准和预期的 Android 行为。

另请阅读文档中标题为 "Shortcut Intents" 的部分,其中包括 gem:

Dynamic shortcuts can be published with any set of Intent flags. Typically, FLAG_ACTIVITY_CLEAR_TASK is specified, possibly along with other flags; otherwise, if the app is already running, the app is simply brought to the foreground, and the target activity may not appear.

您需要重新考虑您的导航,以便它对用户有意义(并且它遵循标准 Android 模式)。

所以我终于找到了解决办法。感谢 David Wasser 提供的一些有用信息。

首先,应用程序快捷方式适用于 Activity,具有操作 MAIN 和类别 LAUNCHER

所以在清单中,我将以下意图过滤器添加到我的 ComposeActivity

 <Activity android:name=".view.activity.ComposeActivity"
     android:relinquishTaskIdentity="true">
     <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
     </intent-filter> 
 </Activity>

如果你仔细看我也设置了android:relinquishTaskIdentity="true"。这确保如果我已经从快捷方式打开 ComposeActivity,然后我可以再次使用它并打开 ComposeActivity。

接下来我更新了用于快捷方式的 Intent

new Intent(context, ComposeActivity.class))
.setAction(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_LAUNCHER)
.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)

通过这样做,如果 ComposeActivity 不在 activity 堆栈顶部,它将始终打开。它还将在任何现有 activity 之上打开。

但是有一个问题。如果没有 activity 打开,那么 Compose 将不会在其下方有任何 activity。如果按下后退按钮,应用程序将关闭。

你可以做的一件事是

@Override
public void onBackPressed() {
    if(isTaskRoot()){
        if (getIntent().hasCategory(Intent.CATEGORY_LAUNCHER) 
              && Intent.ACTION_MAIN.equals(getIntent().getAction())) {
            //launch any activity
        }
    }
    finish();
}

有了这个,当 ComposeActivity 是后台堆栈中唯一的 activity 时,我可以打开任何 activity。就我而言,我启动了 HomeActivity.