Fornecer navegação personalizada no sentido contrário

Os usuários navegam para trás nas telas usando a navegação de retorno. A maioria dos dispositivos Android tem um botão "Voltar" físico, de software ou baseado em gestos. Normalmente, não é necessário adicionar um botão "Voltar" ao app. No entanto, os dispositivos Android Automotive OS (AAOS) no modo de compatibilidade usam um botão "Voltar" do sistema. Isso processa a navegação, então não é necessário adicionar a sua. Para mais detalhes, consulte Modo de compatibilidade do AAOS.

O Android mantém uma pilha de retorno de destinos à medida que o usuário navega no seu app. Isso normalmente permite que o Android navegue adequadamente para destinos anteriores quando o botão "Voltar" é pressionado. No entanto, há casos em que seu app precisa implementar um comportamento de retorno próprio para fornecer a melhor experiência do usuário possível. Por exemplo, ao usar um WebView, convém modificar o comportamento padrão do botão "Voltar" para permitir que o usuário navegue de volta pelo histórico de navegação da Web em vez das telas anteriores no seu app.

Implementar a navegação de retorno personalizada no Compose

No Jetpack Compose, é possível processar a navegação de retorno personalizada usando o elemento combinável BackHandler.

Ao usar o Navigation Compose, geralmente usamos NavController.navigateUp() ou NavController.popBackStack() para navegar até a tela anterior na backstack. No entanto, BackHandler é útil para casos em que você quer implementar um comportamento personalizado quando o usuário pressiona o botão "Voltar" do sistema ou usa o gesto de volta. Por exemplo, se você estiver mostrando um WebView no seu app, talvez queira permitir que os usuários naveguem de volta pelo histórico de navegação quando pressionarem o botão "Voltar" do sistema.

Se você tiver vários elementos combináveis BackHandler ativados em diferentes níveis da árvore de elementos combináveis, apenas o mais interno vai interceptar o evento de retorno.

Implementar a navegação de retorno personalizada com Views

ComponentActivity, a classe base de FragmentActivity e AppCompatActivity, permite controlar o comportamento do botão "Voltar" usando o OnBackPressedDispatcher, que pode ser recuperado chamando getOnBackPressedDispatcher().

O OnBackPressedDispatcher controla como os eventos do botão "Voltar" são enviados para um ou mais objetos OnBackPressedCallback. O construtor de OnBackPressedCallback aceita um valor booleano para o estado inicial ativado. Somente quando um callback estiver ativado, por exemplo, quando isEnabled() retornar true, o agente chamará o handleOnBackPressed() do callback para processar o evento do botão "Voltar". Você pode alterar o estado ativado chamando setEnabled().

Os callbacks são adicionados usando os métodos addCallback. Use o método addCallback(), que usa um LifecycleOwner. Assim, o OnBackPressedCallback só será adicionado quando o LifecycleOwner for Lifecycle.State.STARTED. A atividade também remove os callbacks registrados quando o LifecycleOwner associado é destruído, o que evita vazamentos de memória e o torna adequado para uso em fragmentos ou outros proprietários de ciclo de vida que têm um ciclo de vida mais curto que a atividade.

Veja um exemplo de implementação de callback:

Kotlin

class MyFragment : Fragment() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // This callback will only be called when MyFragment is at least Started.
        val callback = requireActivity().onBackPressedDispatcher.addCallback(this) {
            // Handle the back button event
        }

        // The callback can be enabled or disabled here or in the lambda
    }
    ...
}

Java

public class MyFragment extends Fragment {

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // This callback will only be called when MyFragment is at least Started.
        OnBackPressedCallback callback = new OnBackPressedCallback(true /* enabled by default */) {
            @Override
            public void handleOnBackPressed() {
                // Handle the back button event
            }
        };
        requireActivity().getOnBackPressedDispatcher().addCallback(this, callback);

        // The callback can be enabled or disabled here or in handleOnBackPressed()
    }
    ...
}

Você pode fornecer vários callbacks usando addCallback(). Ao fazer isso, os callbacks são invocados na ordem inversa em que são adicionados. O último callback adicionado é o primeiro que tem a chance de manipular o evento do botão "Voltar". Por exemplo, se você tiver adicionado três callbacks (one, two e three) em ordem, eles serão invocados na ordem de three, two e one, respectivamente.

Os callbacks seguem o padrão Cadeia de responsabilidade. Cada callback na cadeia será invocado somente se o callback anterior não tiver sido ativado. Isso significa que, no exemplo anterior, o callback two seria invocado somente se o callback three não tivesse sido ativado. O callback one seria invocado somente se o callback two não tivesse sido ativado e assim por diante.

Quando adicionado usando addCallback(), o callback não é adicionado à cadeia de responsabilidade até que LifecycleOwner entre no estado Lifecycle.State.STARTED.

Alterar o estado ativado em OnBackPressedCallback é altamente recomendável para alterações temporárias porque mantém a ordem descrita acima, o que será particularmente importante se você tiver callbacks registrados em vários proprietários diferentes do ciclo de vida aninhado.

No entanto, nos casos em que você quiser remover o OnBackPressedCallback por completo, chame remove(). Isso geralmente não é necessário porque os callbacks são removidos automaticamente quando o LifecycleOwner associado é destruído.