Iniciar uma atividade a partir de uma notificação

Ao iniciar uma atividade em uma notificação, é necessário preservar a experiência de navegação esperada pelo usuário. Tocar no botão "Voltar" precisa levar o usuário de volta pelo fluxo de trabalho normal do app até a tela inicial, e abrir a tela "Recentes" precisa mostrar a atividade como uma tarefa separada. Para preservar essa experiência de navegação, inicie a atividade em uma nova tarefa.

A abordagem básica para definir o comportamento de toque da notificação é descrita em Criar uma notificação básica. Esta página descreve como configurar uma PendingIntent para a ação da notificação de modo que ela crie uma nova tarefa e uma backstack. A maneira de fazer isso depende do tipo de atividade que você está iniciando:

Atividade comum
Essa é uma atividade que existe como parte do fluxo de UX normal do app. Quando o usuário chega na atividade pela notificação, a nova tarefa precisa incluir uma backstack completa, permitindo que o usuário toque no botão "Voltar" para navegar pela hierarquia do app.
Atividade especial
O usuário só verá essa atividade se ela for iniciada a partir de uma notificação. Basicamente, essa atividade estende a IU da notificação fornecendo informações difíceis de mostrar na própria notificação. Esta atividade não precisa de uma backstack.

Configurar uma atividade normal PendingIntent

Para iniciar uma atividade normal pela notificação, configure o PendingIntent usando TaskStackBuilder para que ele crie uma nova backstack, conforme mostrado a seguir.

Definir a hierarquia de atividades do app

Defina a hierarquia natural das atividades adicionando o atributo android:parentActivityName a cada elemento <activity> no arquivo de manifesto do app. Confira este exemplo:

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

Criar um PendingIntent com uma pilha de retorno

Para iniciar uma atividade que inclua uma backstack de atividades, crie uma instância de TaskStackBuilder e chame addNextIntentWithParentStack(), transmitindo o Intent para a atividade que você quer iniciar.

Contanto que você defina a atividade mãe para cada atividade, conforme descrito anteriormente, é possível chamar getPendingIntent() para receber um PendingIntent que inclua toda a backstack.

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

Se necessário, adicione argumentos a objetos Intent na pilha chamando TaskStackBuilder.editIntentAt(). Às vezes, isso é necessário para garantir que uma atividade na backstack mostre dados significativos quando o usuário navegar até ela.

Em seguida, transmita o PendingIntent para a notificação 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());

Configurar uma atividade especial PendingIntent

Como uma atividade especial que é iniciada por uma notificação não precisa de uma backstack, você pode criar a PendingIntent chamando getActivity(). No entanto, defina as opções de tarefa adequadas no manifesto.

  1. No manifesto, adicione os atributos abaixo ao elemento <activity>.
    android:taskAffinity=""
    Combinada com a sinalização FLAG_ACTIVITY_NEW_TASK usada no código, defina esse atributo em branco para garantir que essa atividade não entre na tarefa padrão do app. Nenhuma tarefa existente que tiver a afinidade padrão do app será afetada.
    android:excludeFromRecents="true"
    Exclui a nova tarefa da tela "Recentes" para que o usuário não navegue acidentalmente de volta a ela.

    Isso é mostrado neste exemplo:

    <activity
        android:name=".ResultActivity"
        android:launchMode="singleTask"
        android:taskAffinity=""
        android:excludeFromRecents="true">
    </activity>
    
  2. Crie e emita a notificação:
    1. Crie uma Intent que inicie a Activity.
    2. Defina o Activity para iniciar em uma tarefa nova e vazia, chamando setFlags() com as sinalizações FLAG_ACTIVITY_NEW_TASK e FLAG_ACTIVITY_CLEAR_TASK.
    3. Crie um PendingIntent chamando getActivity().

    Isso é mostrado neste exemplo:

    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. Transmita PendingIntent para a notificação 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 mais informações sobre as várias opções de tarefa e como a backstack funciona, consulte Tarefas e a backstack.