Uma tarefa é um conjunto de atividades com que os usuários interagem ao tentar fazer algo no app. Essas atividades são organizadas em uma pilha chamada backstack na ordem em que cada atividade é aberta.
Por exemplo, um app de e-mails pode ter uma atividade para mostrar uma lista de novas mensagens. Quando o usuário seleciona uma mensagem, uma nova atividade é aberta para que ele possa ler o conteúdo. Essa nova atividade é adicionada à backstack. Em seguida, quando o usuário tocar ou fizer o gesto de voltar, essa nova atividade será concluída e removida da pilha.
Ciclo de vida de uma tarefa e da backstack dela
A tela inicial do dispositivo é o ponto de partida para a maioria das tarefas. Quando um usuário toca no ícone de um app ou atalho no acesso rápido aos apps ou na tela inicial, a tarefa desse app é trazida para o primeiro plano. Se não houver nenhuma tarefa para o app, uma nova será criada, e a atividade principal do app será aberta como a atividade raiz na pilha.
Quando a atividade atual inicia outra, a nova atividade é enviada para o topo da pilha e recebe o foco. A atividade anterior permanece na pilha, mas é interrompida. Quando uma atividade é interrompida, o sistema mantém o estado atual da interface do usuário. Quando o usuário executa a ação de voltar, a atividade atual é removida da parte de cima da pilha e destruída. A atividade anterior é retomada, e o estado anterior da interface é restaurado.
As atividades na pilha nunca são reorganizadas, apenas enviadas quando iniciadas e removidas quando dispensadas com o botão ou gesto "Voltar". Assim, a backstack opera como uma estrutura último a chegar, primeiro a sair, conforme mostrado na Figura 1.
Conforme o usuário continua a tocar ou fazer o gesto de voltar, cada atividade na pilha é removida para revelar a anterior, até que o usuário retorne à tela inicial ou à atividade que estava em execução quando a tarefa começou. Quando todas as atividades são removidas da pilha, a tarefa deixa de existir.
Comportamento do toque para voltar em atividades raiz da tela de início
As atividades raiz da tela de início são aquelas que declaram um filtro de intent com
ACTION_MAIN e CATEGORY_LAUNCHER. Essas atividades são
únicas porque atuam como pontos de entrada no app pelo acesso rápido aos apps e
são usadas para iniciar uma tarefa.
Quando um usuário toca ou faz o gesto de voltar em uma atividade de tela de início raiz, o sistema processa o evento de maneira diferente, dependendo da versão do Android em execução no dispositivo.
- Comportamento do sistema no Android 11 e versões anteriores
- O sistema encerra a atividade.
- Comportamento do sistema no Android 12 e versões mais recentes
O sistema move a atividade e a tarefa dela para o segundo plano em vez de finalizar a atividade. Esse comportamento corresponde ao padrão do sistema ao sair de um app usando o botão home ou gesto.
Na maioria dos casos, esse comportamento significa que os usuários podem retomar o app mais rapidamente de um estado de aquecimento, em vez de precisar reiniciar completamente o app de um estado de inicialização a frio.
Se você precisar oferecer uma navegação de retorno personalizada, recomendamos usar as APIs Activity do AndroidX em vez de substituir
onBackPressed(). As APIs Activity do AndroidX são automaticamente adiadas para o comportamento adequado do sistema se não houver componentes interceptando o toque em "Voltar" do sistema.No entanto, se o app substituir
onBackPressed()para processar a navegação de retorno e concluir a atividade, atualize a implementação para chamarsuper.onBackPressed()em vez de concluir. Chamarsuper.onBackPressed()move a atividade e a tarefa dela para o segundo plano quando apropriado e oferece uma experiência de navegação mais consistente para os usuários em todos os apps.
Tarefas em segundo e primeiro plano
Uma tarefa é uma unidade coesa que pode ser movida para o segundo plano quando um usuário inicia uma nova tarefa ou acessa a tela inicial. Enquanto estiver em segundo plano, todas as atividades na tarefa serão interrompidas, mas a backstack da tarefa vai permanecer intacta. A tarefa vai perder o foco enquanto outra tarefa é realizada, conforme mostrado na Figura 2. Uma tarefa pode retornar ao primeiro plano para que os usuários possam continuar de onde pararam.
Considere o seguinte fluxo de tarefas para a Tarefa A atual, que tem três atividades na pilha, incluindo duas abaixo da atividade atual:
O usuário usa o botão "Página inicial" ou gesto e inicia um novo app no Acesso rápido aos apps.
Quando a tela inicial aparece, a Tarefa A vai para o segundo plano. Quando o novo app é iniciado, o sistema inicia uma tarefa para ele (tarefa B) com a própria pilha de atividades.
Depois de interagir com esse app, o usuário volta para a tela inicial e seleciona o app que iniciou a Tarefa A.
Agora, a Tarefa A vem para o primeiro plano: as três atividades na pilha estão intactas, e a atividade na parte de cima da pilha é retomada. Nesse ponto, o usuário também pode voltar para a Tarefa B acessando a tela inicial e selecionando o ícone do app que iniciou essa tarefa ou selecionando a tarefa do app na tela de recentes.
Várias instâncias de atividade
Como as atividades na backstack nunca são reorganizadas, se o app permitir que os usuários iniciem uma atividade específica em mais de uma atividade, uma nova instância dessa atividade será criada e enviada para a pilha, em vez de trazer qualquer instância anterior da atividade para o topo. Assim, uma atividade no app pode ser instanciada várias vezes, mesmo em tarefas diferentes, como mostrado na Figura 3.
Se o usuário voltar usando o botão ou gesto "Voltar", as instâncias da atividade serão reveladas na ordem em que foram abertas, cada uma com o próprio estado da interface. No entanto, é possível modificar esse comportamento se você não quiser que uma atividade seja instanciada mais de uma vez. Para mais informações, consulte Gerenciar tarefas.
Ambientes de várias janelas
Quando os apps são executados simultaneamente em um ambiente de várias janelas, com suporte no Android 7.0 (nível 24 da API) e versões mais recentes, o sistema gerencia as tarefas separadamente para cada janela. Cada janela pode ter várias tarefas. O mesmo vale para apps Android em execução em Chromebooks: o sistema gerencia tarefas ou grupos de tarefas por janela.
Resumo do ciclo de vida
Para resumir o comportamento padrão das atividades e tarefas:
Quando a Atividade A inicia a Atividade B, a Atividade A é interrompida, mas o sistema mantém o estado dela, como a posição de rolagem e qualquer texto inserido em formulários. Se o usuário tocar ou usar o gesto de voltar enquanto estiver na atividade B, a atividade A será retomada com o estado restaurado.
Quando o usuário sai de uma tarefa usando o botão ou gesto home, a atividade atual é interrompida e a tarefa vai para o segundo plano. O sistema mantém o estado de cada atividade na tarefa. Se o usuário retomar a tarefa mais tarde selecionando o ícone na tela de início que iniciou a tarefa, ela vai para o primeiro plano e retoma a atividade na parte de cima da pilha.
Se o usuário tocar ou fizer o gesto de voltar, a atividade atual será removida da pilha e destruída. A atividade anterior na pilha é retomada. Quando uma atividade é destruída, o sistema não retém o estado dela.
Esse comportamento é diferente para atividades de inicialização raiz no Android 12 (nível da API 31) e versões mais recentes.
As atividades podem ser instanciadas várias vezes, até mesmo em outras tarefas.
Gerenciar tarefas
O Android gerencia as tarefas e a backstack colocando todas as atividades iniciadas em sucessão na mesma tarefa, em uma pilha do tipo "último a entrar, primeiro a sair". Isso funciona muito bem para a maioria dos apps, e geralmente você não precisa se preocupar com a forma como as atividades são associadas a tarefas ou como elas existem na backstack.
No entanto, talvez você queira interromper o comportamento normal. Por exemplo, talvez você queira que uma atividade no seu app inicie uma nova tarefa quando for iniciada, em vez de ser colocada na tarefa atual. Ou, ao iniciar uma atividade, talvez você queira trazer uma instância dela para frente, em vez de criar uma nova instância na parte de cima da backstack. Ou talvez você queira que a backstack seja limpa de todas as atividades, exceto a atividade raiz, quando o usuário sair da tarefa.
Você pode fazer isso e muito mais usando atributos no elemento de manifesto
<activity> e flags na intent que você transmite para
startActivity().
Estes são os principais atributos de <activity> que podem ser usados para gerenciar
tarefas:
taskAffinitylaunchModeallowTaskReparentingclearTaskOnLaunchalwaysRetainTaskStatefinishOnTaskLaunch
Estas são as principais flags de intent que você pode usar:
As seções a seguir discutem como usar esses atributos de manifesto e flags de intent para definir como as atividades se associam a tarefas e como elas se comportam na backstack.
As seções a seguir também discutem como o sistema representa e gerencia tarefas e atividades na tela de recentes. Normalmente, você permite que o sistema defina como sua tarefa e suas atividades são representadas na tela de recentes, e não precisa modificar esse comportamento. Para mais informações, consulte Tela "Recentes".
Definir modos de inicialização
Os modos de inicialização permitem definir como uma nova instância de uma atividade é associada à tarefa atual. É possível definir modos de inicialização de duas maneiras, descritas nas seções a seguir:
Como usar o arquivo de manifesto
Ao declarar uma atividade no arquivo de manifesto, é possível especificar como ela se associa às tarefas quando é iniciada.
Como usar sinalizações de intent
Ao chamar
startActivity(), é possível incluir uma flag noIntentque declara como (ou se) a nova atividade se associa à tarefa atual.
Portanto, se a atividade A iniciar a atividade B, a atividade B poderá definir no manifesto como ela se associa à tarefa atual, e a atividade A poderá usar uma flag de intent para solicitar como a atividade B pode se associar à tarefa atual.
Se as duas atividades definirem como a atividade B se associa a uma tarefa, a solicitação da atividade A, conforme definido na intent, será priorizada em relação à solicitação da atividade B, conforme definido no manifesto.
Definir modos de inicialização usando o arquivo de manifesto
Ao declarar uma atividade no arquivo de manifesto, é possível especificar como ela
se associa a uma tarefa usando o atributo launchMode
do elemento <activity>.
Há cinco modos de inicialização que podem ser atribuídos ao atributo launchMode:
"standard"- O modo padrão. O sistema cria uma nova instância da atividade na tarefa em que ela foi iniciada e encaminha a intent a ela. A atividade pode ser instanciada várias vezes, cada instância pode pertencer a tarefas diferentes e uma tarefa pode ter várias instâncias.
"singleTop"- Se uma instância da atividade já existir no topo da tarefa atual,
o sistema vai encaminhar a intent à instância com uma chamada ao método
onNewIntent()em vez de criar uma nova instância da atividade. A atividade é instanciada várias vezes, cada instância pode pertencer a tarefas diferentes, e uma tarefa pode ter várias instâncias (mas apenas se a atividade na parte de cima da backstack não for uma instância atual da atividade).
Por exemplo, suponha que a backstack de uma tarefa consista na atividade raiz A com as atividades B, C e D na parte de cima (portanto, a pilha é A-B-C-D, com D na parte de cima). Uma intent chega para uma atividade do tipo D. Se D tiver o modo de inicialização padrão
"standard", uma nova instância da classe será iniciada, e a pilha se tornará A-B-C-D-D. No entanto, se o modo de inicialização de D for"singleTop", a instância atual de D vai receber a intent poronNewIntent(), porque está no topo da pilha, e a pilha vai permanecer como A-B-C-D. Por outro lado, se uma intent chegar para uma atividade do tipo B, uma nova instância de B será adicionada à pilha, mesmo que o modo de inicialização seja"singleTop"."singleTask"- O sistema recria a atividade na raiz de uma nova tarefa ou localiza a
atividade em uma tarefa existente com a mesma afinidade. Se uma instância da
atividade já existir, o sistema vai encaminhar a intent à instância atual
com uma chamada ao método
onNewIntent(), em vez de criar uma nova instância. Enquanto isso, todas as outras atividades acima dela são destruídas.
"singleInstance"- O comportamento é o mesmo que para
"singleTask", exceto pelo fato do sistema não iniciar nenhuma outra atividade na tarefa que contém a instância. A atividade é sempre o único membro da tarefa. Todas as atividades iniciadas por esta são abertas em uma tarefa separada.
"singleInstancePerTask"- A atividade só pode ser executada como a atividade raiz da tarefa, a primeira
que a criou. Portanto, haverá apenas uma instância dessa
atividade em uma tarefa. Ao contrário do modo de inicialização
singleTask, essa atividade pode ser iniciada em várias instâncias em tarefas diferentes se a flagFLAG_ACTIVITY_MULTIPLE_TASKouFLAG_ACTIVITY_NEW_DOCUMENTestiver definida.
Por exemplo, o navegador Android especifica singleTask em <activity> para que a
atividade dele não seja colocada na tarefa do seu app. Em vez disso, uma nova tarefa é iniciada
para o navegador ou uma tarefa em segundo plano do navegador é trazida para o primeiro plano.
Independentemente de uma atividade começar em uma nova tarefa ou na mesma tarefa que
a atividade que a iniciou, o botão e o gesto "Voltar" sempre levam o usuário
à atividade anterior. No entanto, se você iniciar uma atividade que especifica o modo de inicialização
singleTask e uma instância dessa atividade existir em uma tarefa em segundo plano, toda essa tarefa será trazida para o primeiro plano. Nesse ponto, a backstack
inclui todas as atividades da tarefa trazida para o topo da
pilha. A Figura 4 mostra esse tipo de cenário.
"singleTask" é adicionada à backstack. Se a atividade
já fizer parte de uma tarefa em segundo plano com a própria backstack, toda essa
backstack também vai ser trazida para frente, acima da tarefa
atual.Para mais informações sobre como usar modos de inicialização no arquivo de manifesto, consulte a
documentação do elemento <activity>.
Definir modos de inicialização usando flags de intent
Ao iniciar uma atividade, você pode modificar a associação padrão de uma atividade
à tarefa incluindo flags na intent que você envia para
startActivity(). As flags que podem ser usadas para modificar o comportamento padrão
são as seguintes:
FLAG_ACTIVITY_NEW_TASKO sistema inicia a atividade em uma nova tarefa. Se uma tarefa já estiver em execução para a atividade que está sendo iniciada, ela será trazida para o primeiro plano com o último estado restaurado, e a atividade receberá a nova intent em
onNewIntent().Isso produz o mesmo comportamento que o valor
"singleTask"launchModediscutido na seção anterior.FLAG_ACTIVITY_SINGLE_TOPSe a atividade que está sendo iniciada for a atual, no topo da backstack, a instância atual vai receber uma chamada para
onNewIntent()em vez de criar uma nova instância da atividade.Isso produz o mesmo comportamento que o valor
"singleTop"launchModediscutido na seção anterior.FLAG_ACTIVITY_CLEAR_TOPSe a atividade que está sendo iniciada já estiver em execução na tarefa atual, em vez de iniciar uma nova instância dessa atividade, o sistema vai destruir todas as outras atividades acima dela. A intent é enviada para a instância retomada da atividade, agora no topo, por meio de
onNewIntent().Não há valor para o atributo
launchModeque produza esse comportamento.FLAG_ACTIVITY_CLEAR_TOPé usado com mais frequência em conjunto comFLAG_ACTIVITY_NEW_TASK. Quando usadas juntas, essas flags localizam uma atividade em outra tarefa e a colocam em uma posição em que ela pode responder à intent.
Afinidades de identificador
Uma afinidade indica a qual tarefa uma atividade "prefere" pertencer. Por padrão, todas as atividades do mesmo app têm afinidade entre si: elas "preferem" estar na mesma tarefa.
No entanto, é possível modificar a afinidade padrão de uma atividade. Atividades definidas em apps diferentes podem compartilhar uma afinidade, e atividades definidas no mesmo app podem receber afinidades de tarefas diferentes.
É possível modificar a afinidade de uma atividade usando o atributo taskAffinity
do elemento <activity>.
O atributo taskAffinity usa um valor de string que precisa ser diferente do
nome do pacote padrão declarado no elemento <manifest>, porque o
sistema usa esse nome para identificar a afinidade de tarefa padrão do app.
A afinidade surge em duas circunstâncias:
Quando a intent que inicia uma atividade contém a flag
FLAG_ACTIVITY_NEW_TASK.Por padrão, uma nova atividade é iniciada na tarefa da atividade que chamou
startActivity(). Ela é enviada para a mesma backstack do autor da chamada.No entanto, se a intent transmitida para
startActivity()tiver a flagFLAG_ACTIVITY_NEW_TASK, o sistema vai procurar uma tarefa diferente para abrigar a nova atividade. Muitas vezes, essa é uma tarefa nova. No entanto, não precisa ser. Se houver uma tarefa com a mesma afinidade da nova atividade, ela será iniciada nessa tarefa. Caso contrário, iniciará uma nova tarefa.Se essa flag fizer com que uma atividade inicie uma nova tarefa e o usuário usar o botão home ou gesto para sair dela, será preciso haver uma maneira de o usuário voltar para a tarefa. Algumas entidades, como o gerenciador de notificações, sempre iniciam atividades em uma tarefa externa, nunca como parte da própria tarefa. Por isso, elas sempre colocam
FLAG_ACTIVITY_NEW_TASKnas intents que transmitem parastartActivity().Se uma entidade externa puder invocar sua atividade com essa flag, ofereça aos usuários uma maneira independente de voltar, como um ícone na tela de início de um filtro
CATEGORY_LAUNCHERna atividade raiz da tarefa. Para mais informações, consulte Iniciar uma tarefa.Quando uma atividade tem o atributo
allowTaskReparentingdefinido como"true".Nesse caso, a atividade pode ser movida da tarefa em que foi iniciada para a tarefa com que tem afinidade quando essa tarefa é trazida para o primeiro plano.
Por exemplo, suponha que uma atividade que informa as condições climáticas em cidades selecionadas seja definida como parte de um app de viagens. Ela tem a mesma afinidade que outras atividades no mesmo app, a afinidade padrão do app, e pode ser reassociada a esse atributo.
Quando uma das suas atividades inicia a atividade de previsão do tempo, ela inicialmente pertence à mesma tarefa que a sua atividade. No entanto, quando a tarefa do app de viagens vem para o primeiro plano, a atividade de previsão do tempo é reatribuída a essa tarefa e mostrada nela.
Limpar a backstack
Se o usuário deixar uma tarefa por muito tempo, o sistema vai limpar todas as atividades dela, exceto a atividade raiz. Quando o usuário retorna à tarefa, somente a atividade raiz é restaurada. O sistema se comporta dessa maneira com base na suposição de que, após um longo período, os usuários abandonaram o que estavam fazendo antes e estão retornando à tarefa para começar algo novo.
Há alguns atributos de atividade que podem ser usados para modificar esse comportamento:
alwaysRetainTaskState- Quando esse atributo é definido como
"true"na atividade raiz de uma tarefa, o comportamento padrão descrito acima não acontece. A tarefa mantém todas as atividades na pilha, mesmo após um longo período. clearTaskOnLaunchQuando esse atributo é definido como
"true"na atividade raiz de uma tarefa, ela é limpa até a atividade raiz sempre que o usuário sai da tarefa e retorna a ela. Em outras palavras, é o oposto dealwaysRetainTaskState. O usuário sempre retorna à tarefa no estado inicial, mesmo depois de sair dela por apenas um momento.finishOnTaskLaunchEsse atributo é como
clearTaskOnLaunch, mas opera em uma única atividade, não em uma tarefa inteira. Ele também pode fazer com que qualquer atividade seja concluída, exceto a atividade raiz. Quando definido como"true", a atividade permanece como parte da tarefa apenas na sessão atual. Se o usuário sair e retornar à tarefa, ela não estará mais presente.
Iniciar uma tarefa
Para configurar uma atividade como o ponto de entrada de uma tarefa, forneça um filtro de intent
com "android.intent.action.MAIN" como a ação especificada e
"android.intent.category.LAUNCHER" como a categoria especificada:
<activity ... >
<intent-filter ... >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
...
</activity>
Esse filtro de intent mostra um ícone e um rótulo para a atividade na tela de início do app, permitindo que os usuários iniciem a atividade e retornem à tarefa criada por ela.
Essa segunda habilidade é importante. Os usuários precisam conseguir sair de uma tarefa e
voltar a ela mais tarde usando esse inicializador de atividades. Por esse motivo, use apenas
os dois modos de inicialização que marcam as atividades como sempre iniciando uma tarefa,
"singleTask" e "singleInstance", quando a atividade tiver um filtro
ACTION_MAIN e um filtro CATEGORY_LAUNCHER.
Por exemplo, imagine o que pode acontecer se o filtro estiver ausente: uma
intent inicia uma atividade "singleTask", iniciando uma nova tarefa, e o usuário
passa algum tempo trabalhando nela. Em seguida, o usuário usa o botão ou gesto
home. A tarefa será enviada para o segundo plano e não ficará visível. Agora, o usuário
não tem como retornar à tarefa, porque ela não está representada no acesso rápido
aos apps.
Para os casos em que você não quer que o usuário possa retornar a uma
atividade, defina o finishOnTaskLaunch do elemento <activity> como
"true". Para mais informações, consulte Limpar a backstack.
Para mais informações sobre como as tarefas e atividades são representadas e gerenciadas na tela de recentes, consulte Tela de recentes.