从通知启动 Activity

当您从通知启动 Activity 时,必须保留用户的预期导航体验。点按“返回”应该让用户通过应用的正常工作流程返回到主屏幕,而打开“最近”屏幕应该将 Activity 显示为一项单独的任务。为了保留该导航体验,您应该在新的任务中启动 Activity。

创建通知一文中介绍了为通知设置点按行为的基本方法,而此页面介绍了如何为通知的操作设置 PendingIntent,以便它可以创建新的任务和返回堆栈。但是,具体操作取决于您需要启动的 Activity 类型:

常规 Activity
这类 Activity 是应用的正常用户体验流程的一部分。因此,当用户从通知转到这类 Activity 时,新任务应包括完整的返回堆栈,以便用户可以按“返回”按钮并沿应用层次结构向上导航。
特殊 Activity
只有当 Activity 从通知启动时,用户才可以看到此类 Activity。从某种意义上来说,这类 Activity 通过提供通知本身难以显示的信息来扩展通知界面。因此,这类 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)
    }
    

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);
    

如有必要,您可以通过调用 TaskStackBuilder.editIntentAt() 向堆栈中的 Intent 对象添加参数。有时候需要这样做,以确保在用户向上导航到返回堆栈中的 Activity 时,该 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. 通过使用 FLAG_ACTIVITY_NEW_TASKFLAG_ACTIVITY_CLEAR_TASK 标记调用 setFlags(),将 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
        )
        

    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
        );
        
  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());
        

如需详细了解各个任务选项以及返回堆栈的运作方式,请参阅任务和返回堆栈。如需查看使用通知的示例代码,请参阅 Android 通知示例