从通知启动 Activity

从通知启动 Activity 时,必须保留用户预期的导航体验。轻触“返回”按钮必须让用户沿着应用正常工作流程返回到主屏幕,并且打开“最近使用”屏幕必须将该 Activity 显示为单独的任务。为了保留这种导航体验,请在一个全新的任务中启动 Activity。

设置通知轻触行为的基本方法在创建基本通知中进行了介绍。本页介绍如何为通知的操作设置 PendingIntent,使其创建一个全新的任务和返回堆栈。具体做法取决于你启动的 Activity 类型

常规 Activity
这是一种作为应用正常 UX 流程一部分而存在的 Activity。当用户从通知到达该 Activity 时,新任务必须包含完整的返回堆栈,以便用户可以轻触“返回”按钮向上浏览应用层级结构。
特殊 Activity
用户只有在从通知启动此 Activity 时才能看到它。从某种意义上说,此 Activity 通过提供难以在通知本身中显示的信息来扩展通知 UI。此 Activity 不需要返回堆栈。

设置常规 Activity 的 PendingIntent

要从通知启动常规 Activity,请使用 TaskStackBuilder 设置 PendingIntent,以便按如下所示创建一个新的返回堆栈。

定义应用的 Activity 层级结构

通过在应用清单文件中的每个 <activity> 元素中添加 android:parentActivityName 属性来定义 Activity 的自然层级结构。请参阅以下示例

<activity
    android:name=".MainActivity"
    android:label="@string/app_name" >
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>
<!-- MainActivity is the parent for ResultActivity. -->
<activity
    android:name=".ResultActivity"
    android:parentActivityName=".MainActivity" />
    ...
</activity>

构建带返回堆栈的 PendingIntent

要启动包含 Activity 返回堆栈的 Activity,请创建 TaskStackBuilder 实例并调用 addNextIntentWithParentStack(),将你要启动的 Activity 的 Intent 传递给它。

只要你如前所述为每个 Activity 定义了父 Activity,就可以调用 getPendingIntent() 来获取包含整个返回堆栈的 PendingIntent

Kotlin

// Create an Intent for the activity you want to start.
val resultIntent = Intent(this, ResultActivity::class.java)
// Create the TaskStackBuilder.
val resultPendingIntent: PendingIntent? = TaskStackBuilder.create(this).run {
    // Add the intent, which inflates the back stack.
    addNextIntentWithParentStack(resultIntent)
    // Get the PendingIntent containing the entire back stack.
    getPendingIntent(0,
            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
}

Java

// Create an Intent for the activity you want to start.
Intent resultIntent = new Intent(this, ResultActivity.class);
// Create the TaskStackBuilder and add the intent, which inflates the back
// stack.
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addNextIntentWithParentStack(resultIntent);
// Get the PendingIntent containing the entire back stack.
PendingIntent resultPendingIntent =
        stackBuilder.getPendingIntent(0,
            PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);

如有必要,你可以通过调用 TaskStackBuilder.editIntentAt() 向堆栈中的 Intent 对象添加参数。有时需要这样做以确保返回堆栈中的 Activity 在用户导航到它时显示有意义的数据。

然后,你可以照常将 PendingIntent 传递给通知

Kotlin

val builder = NotificationCompat.Builder(this, CHANNEL_ID).apply {
    setContentIntent(resultPendingIntent)
    ...
}
with(NotificationManagerCompat.from(this)) {
    notify(NOTIFICATION_ID, builder.build())
}

Java

NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID);
builder.setContentIntent(resultPendingIntent);
...
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
notificationManager.notify(NOTIFICATION_ID, builder.build());

设置特殊 Activity 的 PendingIntent

由于从通知启动的特殊 Activity 不需要返回堆栈,因此你可以通过调用 getActivity() 来创建 PendingIntent。但是,请在清单中定义适当的任务选项。

  1. 在清单中,向 <activity> 元素添加以下属性。
    android:taskAffinity=""
    结合你在代码中使用的 FLAG_ACTIVITY_NEW_TASK 标记,将此属性设为空白,以确保此 Activity 不会进入应用的默认任务。任何具有应用默认亲和性的现有任务不受影响。
    android:excludeFromRecents="true"
    将新任务从“最近使用”屏幕中排除,这样用户就不会意外地导航回该任务。

    如下例所示

    <activity
        android:name=".ResultActivity"
        android:launchMode="singleTask"
        android:taskAffinity=""
        android:excludeFromRecents="true">
    </activity>
  2. 构建和发出通知
    1. 创建一个启动 ActivityIntent
    2. 通过调用 setFlags() 并传入标记 FLAG_ACTIVITY_NEW_TASKFLAG_ACTIVITY_CLEAR_TASK,将 Activity 设置为在新任务(空任务)中启动。
    3. 通过调用 getActivity() 创建 PendingIntent

    如下例所示

    Kotlin

    val notifyIntent = Intent(this, ResultActivity::class.java).apply {
        flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
    }
    val notifyPendingIntent = PendingIntent.getActivity(
            this, 0, notifyIntent,
            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
    )

    Java

    Intent notifyIntent = new Intent(this, ResultActivity.class);
    // Set the Activity to start in a new, empty task.
    notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                        | Intent.FLAG_ACTIVITY_CLEAR_TASK);
    // Create the PendingIntent.
    PendingIntent notifyPendingIntent = PendingIntent.getActivity(
            this, 0, notifyIntent,
            PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
    );
  3. 照常将 PendingIntent 传递给通知

    Kotlin

    val builder = NotificationCompat.Builder(this, CHANNEL_ID).apply {
        setContentIntent(notifyPendingIntent)
        ...
    }
    with(NotificationManagerCompat.from(this)) {
        notify(NOTIFICATION_ID, builder.build())
    }

    Java

    NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID);
    builder.setContentIntent(notifyPendingIntent);
    ...
    NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
    notificationManager.notify(NOTIFICATION_ID, builder.build());

如需详细了解各种任务选项以及返回堆栈的工作原理,请参阅任务和返回堆栈