Cómo iniciar una actividad desde una notificación

Cuando inicias una actividad desde una notificación, debes preservar la experiencia de navegación del usuario. Cuando el usuario presiona Atrás, debería retroceder a la pantalla principal mediante el flujo de trabajo normal de tu app. Asimismo, al abrir la pantalla Recientes, se debería mostrar la actividad como una tarea separada. Para preservar esta experiencia de navegación, deberías iniciar la actividad en una tarea nueva.

Si bien el enfoque básico de configuración del comportamiento cuando se presiona tu notificación se describe en Cómo crear una notificación, en esta página se explica cómo configurar un PendingIntent para la acción de tu notificación de manera que se cree una nueva tarea y una pila de actividades. Sin embargo, la manera de hacerlo dependerá de qué tipo de actividad quieres iniciar:

Actividad normal
Corresponde a una actividad que forma parte del flujo normal de la experiencia del usuario de tu app. Por lo tanto, cuando el usuario llegue a la actividad desde la notificación, la próxima tarea debería incluir una pila de actividades completa, que le permita presionar Atrás y navegar hacia arriba en la jerarquía de la app.
Actividad especial
El usuario solamente ve esta actividad si se inicia desde una notificación. En cierto modo, esta actividad extiende la IU de la notificación al proporcionar información que sería difícil de mostrar en la notificación. Por lo tanto, esta actividad no necesita una pila de actividades.

Cómo configurar un PendingIntent de actividad normal

Para iniciar una "actividad normal" desde tu notificación, configura el PendingIntent con TaskStackBuilder de modo que se cree una nueva pila de actividades de la siguiente manera.

Cómo definir la jerarquía de actividades de tu app

Para definir la jerarquía natural de tus actividades, agrega el atributo android:parentActivityName en cada elemento <activity> del archivo de manifiesto de tu app. Por ejemplo:

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

Cómo compilar un PendingIntent con una pila de actividades

Si quieres iniciar una actividad que incluya una pila de actividades, necesitas crear una instancia de TaskStackBuilder, llamar a addNextIntentWithParentStack() y pasar el Intent de la actividad que quieres iniciar.

Siempre y cuando hayas definido la actividad principal para cada actividad como se describe más arriba, puedes llamar a getPendingIntent() a fin de recibir un PendingIntent que incluya toda la pila de actividades.

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

Si es necesario, puedes agregar argumentos a los objetos Intent de la pila mediante una llamada a TaskStackBuilder.editIntentAt(). A veces debes realizar esta acción para asegurarte de que una actividad de la pila de actividades muestre datos útiles cuando el usuario navega por ella.

Luego, puedes pasar el PendingIntent a la notificación como lo haces normalmente:

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

Cómo configurar un PendingIntent de actividad especial

Como una "actividad especial" que se inició desde una notificación no necesita una pila de actividades, puedes llamar a getActivity() para crear el PendingIntent, aunque también deberías asegurarte de definir las opciones de la tarea apropiadas en el manifiesto.

  1. En tu manifiesto, agrega los siguientes atributos al elemento <activity>.
    android:taskAffinity=""
    Junto con la marca FLAG_ACTIVITY_NEW_TASK que usarás en el código, dejar este atributo en blanco garantiza que esta actividad no se incluya en la tarea predeterminada de tu app. Las tareas existentes que tengan la afinidad predeterminada de la app no se verán afectadas.
    android:excludeFromRecents="true"
    Excluye la nueva tarea de Recientes a fin de que el usuario no pueda retroceder accidentalmente a ella.

    Por ejemplo:

        <activity
            android:name=".ResultActivity"
            android:launchMode="singleTask"
            android:taskAffinity=""
            android:excludeFromRecents="true">
        </activity>
        
  2. Crea y emite la notificación:
    1. Crea un Intent que inicie la Activity.
    2. Establece la Activity para iniciar una tarea nueva vacía llamando a setFlags() con las marcas FLAG_ACTIVITY_NEW_TASK y FLAG_ACTIVITY_CLEAR_TASK.
    3. Llama a getActivity() para crear un PendingIntent.

    Por ejemplo:

    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. Luego, puedes pasar el PendingIntent a la notificación como lo haces normalmente:

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

Para obtener más información sobre las diferentes opciones de tareas y cómo funciona la pila de actividades, lee Tareas y pila de actividades. Para ver un código de ejemplo que usa notificaciones, consulta Ejemplo de notificaciones de Android.