Participe do evento ⁠#Android11: apresentação de lançamento da versão Beta no dia 3 de junho.

Transmitir dados entre destinos

O componente de navegação permite que você anexe dados a uma operação de navegação definindo argumentos para um destino. Por exemplo, um destino de perfil de usuário pode usar um argumento de ID do usuário para determinar qual usuário exibir.

Em geral, recomendamos que você dê preferência para a transmissão da quantidade mínima de dados entre destinos. Por exemplo, transmita uma chave para recuperar um objeto em vez de transmitir o próprio objeto, já que o espaço total para todos os estados salvos é limitado no Android. Se você precisar transmitir grandes quantidades de dados, use um ViewModel, conforme descrito em Compartilhar dados entre fragmentos.

Definir argumentos de destino

Para transmitir dados entre destinos, primeiro defina o argumento adicionando-o ao destino que o recebe seguindo estas etapas:

  1. No Navigation Editor, clique no destino que recebe o argumento.
  2. No painel Attributes, clique em Add (+).
  3. Na janela Add Argument Link que é exibida, insira o nome do argumento, o tipo dele, se ele é anulável e um valor padrão, se necessário.
  4. Clique em Add. O argumento aparecerá na lista Arguments no painel Attributes.
  5. Clique na ação correspondente que o leva a esse destino. No painel Attributes, você verá seu argumento recém-adicionado na seção Argument Default Values.
  6. Veja que o argumento foi adicionado em XML. Clique na guia Text para alternar para a visualização XML e observe que seu argumento foi adicionado ao destino que o recebe. Veja um exemplo abaixo:

     <fragment android:id="@+id/myFragment" >
             <argument
                 android:name="myArg"
                 app:argType="integer"
                 android:defaultValue="0" />
         </fragment>
        

Tipos de argumentos compatíveis

A biblioteca Navigation é compatível com os seguintes tipos de argumento:

Tipo Sintaxe app:argType Compatível com valores padrão? Compatível com valores nulos?
Número inteiro app:argType="integer" Sim Não
Flutuante app:argType="float" Sim Não
Longo app:argType="long" Sim: os valores padrão precisam sempre terminar com um sufixo "L" (por exemplo, "123L"). Não
Booleano app:argType="boolean" Sim: "verdadeiro" ou "falso" Não
String app:argType="string" Sim Sim
Referência de recursos app:argType="reference" Sim: os valores padrão precisam estar no formato "@resourceType/resourceName" (por exemplo, "@style/myCustomStyle") ou "0" Não
Parcelable personalizado app:argType="<type>", em que <type> é o nome da classe totalmente qualificado do Parcelable Compatível com um valor padrão de "@null". Não é compatível com outros valores padrão. Sim
Serializável personalizado app:argType="<type>", em que <type> é o nome da classe totalmente qualificado do Serializable Compatível com um valor padrão de "@null". Não é compatível com outros valores padrão. Sim
Enumeração personalizada app:argType="<type>", em que <type> é o nome totalmente qualificado da enumeração Sim: os valores padrão precisam corresponder ao nome não qualificado (por exemplo, "SUCCESS" para corresponder a MyEnum.SUCCESS). Não

Se um tipo de argumento for compatível com valores nulos, você poderá declarar um valor padrão de null usando android:defaultValue="@null".

Quando você escolhe um dos tipos personalizados, a caixa de diálogo Select Class é exibida e solicita que você escolha a classe correspondente para esse tipo. A guia Project permite escolher uma classe do projeto atual.

Escolha o <inferred type> (tipo inferido) para fazer com que a biblioteca "Navigation" determine o tipo com base no valor fornecido.

Marque Array para indicar que o argumento precisa ser uma matriz do valor de Type (tipo) selecionado. Observe que matrizes de enumerações e matrizes de referências de recursos não são compatíveis. As matrizes são sempre anuláveis, independentemente da nulidade do tipo subjacente. As matrizes são compatíveis com um único valor padrão, "@null". As matrizes não são compatíveis com nenhum outro valor padrão.

Modificar um argumento de destino em uma ação

Argumentos e valores padrão no nível de destino são usados por todas as ações que navegam até o destino. Se necessário, modifique o valor padrão de um argumento (ou defina um, se ele ainda não existir), definindo um argumento no nível da ação. Esse argumento precisa ter o mesmo nome e tipo que o argumento declarado no destino.

O XML abaixo declara uma ação com um argumento que modifica o do nível de destino do exemplo acima:

<action android:id="@+id/startMyFragment"
        app:destination="@+id/myFragment">
        <argument
            android:name="myArg"
            app:argType="integer"
            android:defaultValue="1" />
    </action>
    

Usar o Safe Args para transmitir dados com a segurança de tipo

O componente de navegação tem um plug-in para Gradle chamado Safe Args que gera classes simples de objeto e builder para navegação com segurança de tipo e acesso a qualquer argumento associado. O Safe Args é altamente recomendado para a navegação e a transmissão de dados, porque garante a segurança de tipo.

Em alguns casos, por exemplo, se você não estiver usando o Gradle, não será possível usar o plug-in Safe Args. Nessas situações, você pode usar Bundles para transmitir dados diretamente.

Para adicionar Safe Args ao seu projeto, inclua o seguinte classpath no seu arquivo build.gradle de nível superior:

buildscript {
    repositories {
        google()
    }
    dependencies {
        def nav_version = "2.3.0-alpha06"
        classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
    }
}

Você também precisa aplicar um dos dois plug-ins disponíveis.

Para gerar um código de linguagem Java adequado para Java ou módulos Java e Kotlin mistos, adicione esta linha ao arquivo build.gradle do seu app ou módulo:

apply plugin: "androidx.navigation.safeargs"

Como alternativa, para gerar o código Kotlin adequado para módulos somente Kotlin, adicione:

apply plugin: "androidx.navigation.safeargs.kotlin"

Você precisa ter android.useAndroidX=true no arquivo gradle.properties, como mostrado em Migrar para o AndroidX.

Depois de ativar o Safe Args, o código gerado conterá as seguintes classes e métodos de segurança de tipos para cada ação, bem como para cada destino de envio e recebimento.

  • Uma classe é criada para cada destino no qual uma ação se origina. O nome dessa classe é o nome do destino de origem, anexado com a palavra "Directions". Por exemplo, se o destino de origem for um fragmento com o nome SpecifyAmountFragment, a classe gerada será chamada de SpecifyAmountFragmentDirections.

    Essa classe tem um método para cada ação definida no destino de origem.

  • Para cada ação usada para transmitir o argumento, é criada uma classe interna cujo nome vem da ação. Por exemplo, se a ação for chamada de confirmationAction,, a classe será denominada ConfirmationAction. Se a ação contiver argumentos sem defaultValue, use a classe de ação associada para definir o valor dos argumentos.

  • Uma classe é criada para o destino de recebimento. O nome dessa classe é o nome do destino, anexado com a palavra "Args". Por exemplo, se o fragmento de destino tiver o nome ConfirmationFragment,, a classe gerada será chamada ConfirmationFragmentArgs. Use o método fromBundle() dessa classe para recuperar os argumentos.

O exemplo a seguir mostra como usar esses métodos para definir um argumento e transmiti-lo ao método navigate():

Kotlin

    override fun onClick(v: View) {
       val amountTv: EditText = view!!.findViewById(R.id.editTextAmount)
       val amount = amountTv.text.toString().toInt()
       val action = SpecifyAmountFragmentDirections.confirmationAction(amount)
       v.findNavController().navigate(action)
    }
    

Java

    @Override
    public void onClick(View view) {
       EditText amountTv = (EditText) getView().findViewById(R.id.editTextAmount);
       int amount = Integer.parseInt(amountTv.getText().toString());
       ConfirmationAction action =
               SpecifyAmountFragmentDirections.confirmationAction()
       action.setAmount(amount)
       Navigation.findNavController(view).navigate(action);
    }
    

No código do destino de recebimento, use o método getArguments() para recuperar o pacote e usar o conteúdo. Ao usar as dependências -ktx, os usuários do Kotlin também podem usar a delegação de propriedade by navArgs() para acessar argumentos.

Kotlin

    val args: ConfirmationFragmentArgs by navArgs()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        val tv: TextView = view.findViewById(R.id.textViewAmount)
        val amount = args.amount
        tv.text = amount.toString()
    }
    

Java

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        TextView tv = view.findViewById(R.id.textViewAmount);
        int amount = ConfirmationFragmentArgs.fromBundle(getArguments()).getAmount();
        tv.setText(amount + "")
    }
    

Usar o Safe Args com uma ação global

Ao usar o Safe Args com uma ação global, é necessário fornecer um valor android:id para o elemento raiz <navigation>, como mostrado no exemplo a seguir:

    <?xml version="1.0" encoding="utf-8"?>
    <navigation xmlns:app="http://schemas.android.com/apk/res-auto"
                xmlns:tools="http://schemas.android.com/tools"
                xmlns:android="http://schemas.android.com/apk/res/android"
                android:id="@+id/main_nav"
                app:startDestination="@id/mainFragment">

        ...

    </navigation>
    

O componente de navegação gera uma classe Directions para o elemento <navigation> com base no valor android:id. Por exemplo, se você tiver um elemento <navigation> com android:id=@+id/main_nav, a classe gerada será chamada MainNavDirections. Todos os destinos no elemento <navigation> têm métodos gerados para acessar todas as ações globais associadas usando os mesmos métodos descritos na seção anterior.

Transmitir dados entre destinos com objetos Bundle

Se você não estiver usando o Gradle, ainda poderá transmitir argumentos entre destinos usando objetos Bundle. Crie um objeto Bundle e o transmita para o destino usando navigate(), como mostrado abaixo:

Kotlin

    var bundle = bundleOf("amount" to amount)
    view.findNavController().navigate(R.id.confirmationAction, bundle)
    

Java

    Bundle bundle = new Bundle();
    bundle.putString("amount", amount);
    Navigation.findNavController(view).navigate(R.id.confirmationAction, bundle);
    

No código do destino de recebimento, use o método getArguments() para recuperar o Bundle e usar o conteúdo:

Kotlin

    val tv = view.findViewById<TextView>(R.id.textViewAmount)
    tv.text = arguments?.getString("amount")
    

Java

    TextView tv = view.findViewById(R.id.textViewAmount);
    tv.setText(getArguments().getString("amount"));
    

Transmitir dados para o destino inicial

Você pode transmitir dados para o destino inicial do seu app. Primeiro, construa explicitamente um Bundle que mantenha os dados. Em seguida, use um dos métodos a seguir para transmitir o Bundle para o destino inicial:

Para recuperar os dados no destino inicial, chame Fragment.getArguments().

Considerações sobre o ProGuard

Se você estiver reduzindo seu código, precisará impedir que os nomes de classes Parcelable, Serializable e Enum sejam ofuscados como parte do processo de minificação. Isso pode ser feito de duas maneiras:

Usar anotações @Keep

O exemplo abaixo adiciona as anotações @Keep a definições de classe de modelo:

Kotlin

    @Keep class ParcelableArg : Parcelable { ... }

    @Keep class SerializableArg : Serializable { ... }

    @Keep enum class EnumArg { ... }
    

Java

    @Keep public class ParcelableArg implements Parcelable { ... }

    @Keep public class SerializableArg implements Serializable { ... }

    @Keep public enum EnumArg { ... }
    

Usar regras keepnames

Você também pode adicionar regras keepnames ao seu arquivo proguard-rules.pro, como mostrado no exemplo a seguir:

proguard-rules.pro

...

    -keepnames class com.path.to.your.ParcelableArg
    -keepnames class com.path.to.your.SerializableArg
    -keepnames class com.path.to.your.EnumArg

    ...
    

Outros recursos

Para saber mais sobre navegação, consulte os seguintes recursos.

Amostras

Codelabs

Vídeos