O Google tem o compromisso de promover a igualdade racial para as comunidades negras. Saiba como.

Entenda as tarefas e a pilha de retorno

Uma tarefa é um conjunto de atividades com as quais os usuários interagem ao realizar um determinado job. As atividades são organizadas em uma pilha, a pilha de retorno, 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 ver essa mensagem. Essa nova atividade é adicionada à pilha de retorno. Se o usuário pressionar o botão Voltar, a nova atividade será encerrada e retirada da pilha. O vídeo a seguir fornece uma boa visão geral de como a pilha de retorno funciona.

Quando apps estão em execução simultaneamente em um ambiente com várias janelas, compatível com o Android 7.0 (API de nível 24) e posterior, o sistema gerencia as tarefas separadamente para cada janela. Cada uma delas pode ter várias tarefas. O mesmo vale para apps para Android em execução em Chromebooks: o sistema gerencia tarefas, ou grupos de tarefas, uma janela por vez.

A tela inicial do dispositivo é o local de início da maioria das tarefas. Quando o usuário toca em um ícone no Acesso rápido aos apps ou em um atalho na tela inicial, a tarefa desse app aparece em primeiro plano. Se não houver nenhuma tarefa para o app, caso o app não tenha sido usado recentemente, uma nova tarefa será criada e a atividade "principal" do app será aberta como a atividade raiz na pilha.

Quando a atividade atual iniciar outra, a nova atividade será empurrada para a parte superior da pilha e receberá 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 pressiona o botão Voltar, a atividade atual é exibida na parte superior da pilha (a atividade é destruída) e a atividade anterior é retomada (o estado anterior da IU é restaurado). As atividades na pilha nunca são reorganizadas, apenas colocadas e retiradas da pilha: colocadas quando iniciadas pela atividade atual e retiradas quando o usuário sai delas usando o botão Voltar. Assim, a pilha de retorno opera como uma estrutura de objeto do tipo “último a entrar, primeiro a sair”. A Figura 1 visualiza esse comportamento com uma linha do tempo mostrando o progresso entre as atividades em conjunto com a pilha de retorno atual em cada ponto no tempo.

Figura 1. Uma representação de como cada nova atividade em uma tarefa adiciona um item à pilha de retorno. Quando o usuário pressiona o botão Voltar, a atividade atual é destruída e a anterior é retomada.

Se o usuário continuar pressionando Voltar, cada atividade na pilha será retirada para revelar a anterior, até que o usuário retorne à tela inicial ou à atividade que estava sendo executada quando a tarefa começou. Quando todas as atividades são removidas da pilha, a tarefa deixa de existir.

Figura 2. Duas tarefas: a Tarefa B recebe a interação do usuário em primeiro plano, enquanto a Tarefa A está em segundo plano, aguardando para ser retomada.

Uma tarefa é uma unidade coesa que pode ser movida para o "segundo plano" quando os usuários iniciam uma nova tarefa ou acessam a tela inicial pelo botão home. Enquanto estiver em segundo plano, todas as atividades na tarefa serão interrompidas, mas a pilha de retorno da tarefa permanecerá intacta. A tarefa simplesmente perde o foco enquanto outra tarefa ocorre, como mostrado na Figura 2. Uma tarefa pode retornar ao "primeiro plano" para que os usuários possam continuar de onde pararam. Suponha, por exemplo, que a tarefa atual (Tarefa A) tenha três atividades na pilha, duas sob a atividade atual. O usuário pressiona o botão home e inicia um novo app a partir do Acesso rápido aos apps. Quando a tela inicial é exibida, a Tarefa A passa para o segundo plano. Quando o novo app é iniciado, o sistema inicia uma tarefa para esse app (Tarefa B) com a própria pilha de atividades. Depois de interagir com esse app, o usuário retorna para o Início novamente e seleciona o app que iniciou originalmente a Tarefa A. Agora, a Tarefa A passa para o primeiro plano. Todas as três atividades na pilha dela estão intactas, e a atividade no topo da pilha é retomada. Neste ponto, o usuário também pode voltar para a Tarefa B indo até o Início e selecionando o ícone do aplicativo que iniciou a tarefa ou selecionando a tarefa a partir da tela de visão geral. Este é um exemplo de multitarefa no Android.

Observação: várias tarefas podem ser mantidas em segundo plano ao mesmo tempo. No entanto, se o usuário estiver executando muitas tarefas em segundo plano ao mesmo tempo, o sistema poderá começar a destruir atividades em segundo plano para recuperar memória, fazendo com que os estados de atividade sejam perdidos.

Figura 3. Uma única atividade é instanciada várias vezes.

Como as atividades na pilha de retorno 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 será criada e colocada na pilha, em vez de levar qualquer instância anterior da atividade para o topo. Desse modo, uma atividade no seu app pode ser instanciada várias vezes, mesmo em tarefas diferentes, como mostrado na Figura 3. Desse modo, se o usuário navegar usando o botão Voltar, cada instância da atividade será revelada na ordem em que foram abertas, cada uma com o próprio estado de IU. No entanto, você pode modificar esse comportamento se não quiser que uma atividade seja instanciada mais de uma vez. A forma de fazer isso é discutida na seção sobre Como gerenciar tarefas.

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 o texto inserido nos formulários. Se o usuário pressionar o botão Voltar enquanto estiver na Atividade B, a Atividade A será retomada com o estado restaurado.
  • Quando o usuário sai de uma tarefa pressionando o botão home, a atividade atual é interrompida e a tarefa fica em segundo plano. O sistema retém o estado de cada atividade na tarefa. Se o usuário retomar a tarefa posteriormente selecionando o ícone na tela de início que a abriu, a tarefa passará para o primeiro plano e retomará a atividade na parte superior da pilha.
  • Se o usuário pressionar o botão Voltar, a atividade atual será removida da pilha e destruída. A atividade anterior na pilha será retomada. Quando uma atividade é destruída, o sistema não retém o estado da atividade.
  • As atividades podem ser instanciadas várias vezes, até mesmo em outras tarefas.

Design de navegação

Para saber mais sobre como a navegação de apps funciona no Android, leia o guia sobre como criar gráficos de navegação.

Como gerenciar tarefas

A maneira como o Android gerencia tarefas e a pilha de retorno, como descrito acima, colocando todas as atividades iniciadas em sequência na mesma tarefa e em uma pilha "último a entrar, primeiro a sair", funciona bem para a maioria dos apps, e você não precisa se preocupar em como suas atividades são associadas a tarefas ou como elas existem na pilha de retorno. No entanto, você pode decidir que quer interromper o comportamento normal. Talvez você queira que uma atividade no seu app inicie uma nova tarefa quando ela for iniciada, em vez de ser colocada na tarefa atual. Ou, quando você iniciar uma atividade, talvez queira exibir uma instância existente dela em vez de criar uma nova instância na parte superior da pilha de retorno. Ou talvez queira que sua pilha de retorno seja limpa de todas as atividades, exceto da atividade raiz, quando o usuário sair da tarefa.

Você pode fazer isso e muito mais, com atributos no elemento de manifesto <activity> e com sinalizações no intent que você passar para startActivity().

Com relação a isso, os principais atributos <activity> que você pode usar são:

E as principais sinalizações de intent que você pode usar são:

Nas seções a seguir, você verá como usar esses atributos de manifesto e sinalizações de intent para definir como as atividades são associadas às tarefas e como elas se comportam na pilha de retorno.

Além disso, discutimos separadamente as considerações sobre como tarefas e atividades podem ser representadas e gerenciadas na tela de visão geral. Consulte Tela de visão geral para ver mais informações. Normalmente, você precisa permitir que o sistema defina como a tarefa e as atividades são representadas na tela de visão geral, e não é necessário mudar esse comportamento.

Atenção: a maioria dos apps não interromperá o comportamento padrão de atividades e tarefas. Se você determinar que é necessário modificar os comportamentos padrão para sua atividade, tenha cuidado e teste a usabilidade da atividade durante a inicialização e ao retornar para ela de outras atividades e tarefas com o botão Voltar. Teste os comportamentos de navegação que possam entrar em conflito com o comportamento esperado do usuário.

Como definir modos de inicialização

Os modos de inicialização permitem que você defina como uma nova instância de uma atividade é associada à tarefa atual. Você pode definir diferentes modos de inicialização de duas maneiras:

Desse modo, se a Atividade A iniciar a Atividade B, a Atividade B poderá definir no manifesto como ela será associada à tarefa atual (se for o caso), e a Atividade A também poderá solicitar a associação da Atividade B à tarefa atual. Se ambas as atividades definirem de que modo a Atividade B se associará a uma tarefa, a solicitação da Atividade A, conforme definido no intent, será atendida antes da solicitação da Atividade B, conforme definido no manifesto.

Observação: alguns modos de inicialização disponíveis para o arquivo de manifesto não estão disponíveis como sinalizações de um intent e, da mesma forma, alguns modos de inicialização disponíveis como sinalizações para um intent não podem ser definidos no manifesto.

Como usar o arquivo de manifesto

Ao declarar uma atividade no seu arquivo de manifesto, você pode especificar como a atividade será associada a uma tarefa usando o <activity> do atributo launchMode do elemento.

O atributo launchMode especifica uma instrução sobre como a atividade será iniciada em uma tarefa. Há quatro modos de inicialização diferentes que podem ser atribuídos ao atributo launchMode:

"standard" (o modo padrão)
Padrão. O sistema cria uma nova instância da atividade na tarefa a partir da qual ela foi iniciada e encaminha o intent para 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 na parte superior da tarefa atual, o sistema encaminhará o intent para essa instância por meio de uma chamada para o método onNewIntent(), em vez de criar uma nova instância da atividade. A atividade pode ser instanciada várias vezes, cada instância pode pertencer a diferentes tarefas, e uma tarefa pode ter várias instâncias, mas somente se a atividade na parte superior da pilha de retorno não for uma instância existente da atividade.

Por exemplo, suponha que a pilha de retorno de uma tarefa consista na atividade raiz A com as atividades B, C e D no topo. A pilha é A-B-C-D, D está no topo. Um intent chega para uma atividade do tipo D. Se D tiver o modo de inicialização "standard" padrão, 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 existente de D receberá o intent por onNewIntent(), porque está no topo da pilha. A pilha continua sendo A-B-C-D. Porém, se um 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".

Observação: quando uma nova instância de uma atividade é criada, o usuário pode pressionar o botão Voltar para retornar à atividade anterior. Mas quando uma instância existente de uma atividade gerencia um novo intent, o usuário não pode pressionar o botão Voltar para retornar ao estado da atividade antes da chegada do novo intent em onNewIntent().

"singleTask"
O sistema cria uma nova tarefa e instancia a atividade na raiz dela. No entanto, se uma instância da atividade já existir em uma tarefa separada, o sistema encaminhará o intent para a instância existente por meio de uma chamada para o método onNewIntent(), em vez de criar uma nova instância. Apenas uma instância da atividade pode existir por vez.

Observação: embora a atividade comece em uma nova tarefa, o botão Voltar ainda retorna o usuário à atividade anterior.

"singleInstance".
Trabalha da mesma forma que "singleTask", exceto pelo fato de o sistema não iniciar nenhuma outra atividade na tarefa que contém a instância. A atividade é sempre o único membro da tarefa. Qualquer atividade iniciada por ela será aberta em uma tarefa separada.

Como outro exemplo, o app Navegador Android declara que a atividade do navegador precisa sempre ser aberta na própria tarefa, especificando o modo de inicialização singleTask no elemento <activity>. Isso significa que se o app emitir um intent para abrir o Navegador Android, a atividade não será colocada na mesma tarefa que o app. Em vez disso, uma nova tarefa será iniciada para o Navegador ou, se o Navegador já tiver uma tarefa em execução em segundo plano, essa tarefa será antecipada para lidar com o novo intent.

Não importa se uma atividade começará em uma nova tarefa ou na mesma tarefa que a iniciou, o botão Voltar sempre levará o usuário à atividade anterior. No entanto, se você iniciar uma atividade que especifique o modo de inicialização singleTask e se uma instância dessa atividade existir em uma tarefa em segundo plano, toda a tarefa será trazida para o primeiro plano. Neste ponto, a pilha de retorno inclui todas as atividades da tarefa apresentadas na parte superior da pilha. A Figura 4 ilustra esse tipo de cenário.

Figura 4. Uma representação de como uma atividade com modo de inicialização "singleTask" é adicionada à pilha de retorno. Se a atividade já fizer parte de uma tarefa em segundo plano com a própria pilha de retorno, toda a pilha de retorno também entrará em primeiro plano, sobre a tarefa atual.

Para mais informações sobre o uso de modos de inicialização no arquivo de manifesto, consulte a documentação do elemento <activity>, em que o atributo launchMode e os valores aceitos são mais discutidos.

Observação: os comportamentos que você especifica para sua atividade com o atributo launchMode podem ser substituídos por sinalizações incluídas no intent que inicia sua atividade, conforme discutido na próxima seção.

Como usar sinalizações de intent

Ao iniciar uma atividade, você pode modificar a associação padrão de uma atividade com a tarefa incluindo sinalizações no intent entregue a startActivity(). As sinalizações que você pode usar para modificar o comportamento padrão são:

FLAG_ACTIVITY_NEW_TASK
Iniciar a atividade em uma nova tarefa. Se uma tarefa já estiver em execução para a atividade que você está iniciando, ela será colocada em primeiro plano com o último estado restaurado, e a atividade receberá o novo intent em onNewIntent().

Isso produz o mesmo comportamento que o valor "singleTask" launchMode, discutido na seção anterior.

FLAG_ACTIVITY_SINGLE_TOP
Se a atividade iniciada for a atual, na parte superior da pilha de retorno, a instância existente receberá uma chamada para onNewIntent(), em vez de criar uma nova instância da atividade.

Isso produz o mesmo comportamento que o valor "singleTop" launchMode, discutido na seção anterior.

FLAG_ACTIVITY_CLEAR_TOP
Se a atividade iniciada já estiver em execução na tarefa atual, em vez de lançar uma nova instância dessa atividade, todas as outras atividades acima dela serão destruídas, e este intent será entregue à instância retomada da atividade (agora no topo), por meio de onNewIntent().

Não há valor para o atributo launchMode que produza esse comportamento.

FLAG_ACTIVITY_CLEAR_TOP é mais frequentemente usado em conjunto com FLAG_ACTIVITY_NEW_TASK. Quando usadas em conjunto, essas sinalizações são uma maneira de localizar uma atividade existente em outra e colocá-la em uma posição em que ela possa responder ao intent.

Observação: se o modo de inicialização da atividade designada for "standard", ela também será removida da pilha, e uma nova instância será iniciada no lugar dela para gerenciar o intent de entrada. Isso ocorre porque uma nova instância sempre será criada para um novo intent quando o modo de inicialização for "standard".

Como gerenciar afinidades

A afinidade indica a qual tarefa uma atividade prefere pertencer. Por padrão, todas as atividades do mesmo app têm afinidade umas com as outras. Por padrão, todas as atividades no mesmo app preferem estar na mesma tarefa. Porém, você pode modificar a afinidade padrão de uma atividade. As atividades definidas em apps diferentes podem compartilhar afinidades, enquanto atividades definidas no mesmo app podem receber afinidades de tarefas diferentes.

Você pode modificar a afinidade de qualquer atividade com o atributo taskAffinity do elemento <activity>.

O atributo taskAffinity assume um valor de string, que precisa ser exclusivo do nome de 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 o intent que inicia uma atividade contém a sinalização FLAG_ACTIVITY_NEW_TASK.

    Uma nova atividade é, por padrão, iniciada na tarefa da atividade que chamou startActivity(). Ela é colocada na mesma pilha de retorno como a autora da chamada. Porém, se o intent passado para startActivity() tiver a sinalização FLAG_ACTIVITY_NEW_TASK, o sistema procurará uma tarefa diferente para abrigar a nova atividade. Muitas vezes, essa é uma nova tarefa. No entanto, não precisa ser. Se já houver uma tarefa com a mesma afinidade da nova atividade, ela será iniciada nessa tarefa. Caso contrário, iniciará uma nova tarefa.

    Se essa sinalização fizer com que uma atividade inicie uma nova tarefa e o usuário pressionar o botão home para sair dela, será preciso haver uma forma de o usuário navegar de volta 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, então elas sempre colocam FLAG_ACTIVITY_NEW_TASK nos intents que passam para startActivity(). Se você tiver uma atividade que possa ser invocada por uma entidade externa que possa usar essa sinalização, forneça ao usuário uma forma independente de voltar à tarefa iniciada, como um ícone na tela de início. A atividade raiz da tarefa tem um filtro de intent CATEGORY_LAUNCHER, consulte a seção Como iniciar uma tarefa abaixo.

  • Quando uma atividade tem o atributo allowTaskReparenting definido como "true".

    Nesse caso, quando chegar ao primeiro plano, a atividade poderá ser movida da tarefa iniciada para a tarefa com a qual ela tem afinidade.

    Por exemplo, suponha que uma atividade que informa condições climáticas em cidades selecionadas seja definida como parte de um app de viagem. Ela tem a mesma afinidade que as outras atividades no mesmo app, a afinidade de app padrão, e permite a reassociação com esse atributo. Quando uma das suas atividades inicia a atividade de informações sobre o clima, ela inicialmente pertence à mesma tarefa da sua atividade. No entanto, quando a tarefa do app de viagem fica em primeiro plano, a atividade de informações sobre o clima é reatribuída a essa tarefa e exibida nela.

Dica: se um arquivo APK tiver mais de um "app" do ponto de vista do usuário, você provavelmente usará o atributo taskAffinity para atribuir diferentes afinidades às atividades associadas a cada "app".

Como limpar a pilha de retorno

Se o usuário sair de uma tarefa por um longo período, o sistema limpará a tarefa de todas as atividades, exceto a atividade raiz. Quando o usuário retornar à tarefa, apenas a atividade raiz será restaurada. O sistema se comporta dessa maneira porque, após um período prolongado, os usuários provavelmente abandonaram o que estavam fazendo e estão retornando à tarefa para começar algo novo.

Há alguns atributos de atividade que você pode usar para modificar esse comportamento:

alwaysRetainTaskState
Se esse atributo estiver definido como "true" na atividade raiz de uma tarefa, o comportamento padrão que acabamos de descrever não acontecerá. A tarefa reterá todas as atividades na pilha mesmo após um longo período.
clearTaskOnLaunch
Se esse atributo estiver definido como "true" na atividade raiz de uma tarefa, a pilha será limpa até a atividade raiz sempre que o usuário sair da tarefa e retornar a ela. Em outras palavras, é o oposto de alwaysRetainTaskState. O usuário sempre retorna à tarefa no estado inicial, mesmo depois de deixá-la por apenas um momento.
finishOnTaskLaunch
Esse 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 desativada, incluindo a atividade raiz. Quando ele estiver definido como "true", a atividade continuará sendo parte da tarefa apenas na sessão atual. Se o usuário sair e voltar à tarefa, ela não estará mais presente.

Como iniciar uma tarefa

Você pode configurar uma atividade como ponto de entrada para uma tarefa, fornecendo a ela um filtro de intent com "android.intent.action.MAIN" como a ação especificada e "android.intent.category.LAUNCHER" como a categoria especificada. Por exemplo:

    <activity ... >
        <intent-filter ... >
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
        ...
    </activity>
    

Um filtro de intent desse tipo faz com que um ícone e uma etiqueta para a atividade sejam exibidos no Acesso rápido aos apps, oferecendo aos usuários uma maneira de iniciar a atividade e retornar à tarefa criada a qualquer momento após a inicialização.

Essa segunda habilidade é importante: os usuários precisam conseguir sair de uma tarefa e depois voltar a ela usando esse iniciador de atividades. Por isso, os dois modos de inicialização que marcam atividades como sempre iniciando uma tarefa, "singleTask" e "singleInstance", precisam ser usados somente quando a atividade tiver um filtro ACTION_MAIN e CATEGORY_LAUNCHER. Imagine, por exemplo, o que poderia acontecer se o filtro estivesse ausente: um intent inicia uma atividade "singleTask", iniciando uma nova tarefa, e o usuário passa algum tempo trabalhando nessa tarefa. Em seguida, o usuário pressiona o botão 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 queira que o usuário possa retornar a uma atividade, defina o finishOnTaskLaunch do elemento <activity> como "true". Consulte Como limpar a pilha de retorno.

Mais informações sobre como tarefas e atividades são representadas e gerenciadas na tela Visão geral estão disponíveis em Tela Recentes.

Mais recursos