O componente de navegação permite anexar 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 mostrar.
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 na
Visão geral do ViewModel.
Definir argumentos de destino
Para transmitir dados entre destinos, primeiro defina o argumento adicionando-o ao destino que o recebe seguindo estas etapas:
- No Navigation Editor, clique no destino que recebe o argumento.
- No painel Attributes, clique em Add (+).
- 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.
- Clique em Adicionar. O argumento aparecerá na lista Arguments no painel Attributes.
- Em seguida, clique na ação correspondente que leva você a esse destino. No painel Attributes, você verá seu argumento recém-adicionado na seção Argument Default Values.
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. Confira um exemplo a seguir:
<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 | Compatibilidade com valores padrão | Processado por rotas | Nullable |
---|---|---|---|---|
Número inteiro | app:argType="integer" | Sim | Sim | Não |
Flutuante | app:argType="float" | Sim | Sim | Não |
Longo | app:argType="long" | Sim: os valores padrão precisam sempre terminar com um sufixo "L" (por exemplo, "123L"). | Sim | Não |
Booleano | app:argType="boolean" | Sim: "verdadeiro" ou "falso" | Sim | Não |
String | app:argType="string" | Sim | 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" | Sim | 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. | Nã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. | Não | Sim |
Enumeração personalizada | app:argType="<type>", em que <type> é o nome totalmente qualificado do tipo enumerado | Sim: os valores padrão precisam corresponder ao nome não qualificado (por exemplo, "SUCCESS" para corresponder a MyEnum.SUCCESS). | Não | 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"
.
Rotas, links diretos e URIs com seus argumentos podem ser analisados usando strings. Isso não é possível usando tipos de dados personalizados, como Parcelables e serializadores, conforme visto na tabela anterior. Para transmitir dados complexos personalizados, armazene os dados em outro lugar, como um ViewModel ou banco de dados, e transmita apenas um identificador durante a navegação. Em seguida, recupere os dados no novo local após a conclusão da navegação.
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> 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 selecionado. Observe o seguinte:
- Matrizes de enumerações e matrizes de referências de recursos não são compatíveis.
- As matrizes são compatíveis com valores anuláveis, independentemente da compatibilidade com valores
anuláveis de tipo subjacente. Por exemplo, o uso de
app:argType="integer[]"
permite usarapp:nullable="true"
para indicar que a transmissão de uma matriz nula é aceitável. - 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.
Substituir 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 a seguir declara uma ação com um argumento que substitui o argumento no nível do destino do exemplo anterior:
<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 tipos.
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:
Groovy
buildscript { repositories { google() } dependencies { def nav_version = "2.7.7" classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version" } }
Kotlin
buildscript { repositories { google() } dependencies { val nav_version = "2.7.7" 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 módulos Java ou Java e Kotlin mistos, adicione
esta linha ao arquivo build.gradle
do seu app ou módulo:
Groovy
plugins { id 'androidx.navigation.safeargs' }
Kotlin
plugins { id("androidx.navigation.safeargs") }
Como alternativa, para gerar o código Kotlin adequado para módulos somente Kotlin, adicione:
Groovy
plugins { id 'androidx.navigation.safeargs.kotlin' }
Kotlin
plugins { id("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 contém as classes e os métodos de segurança de tipos abaixo 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 à palavra "Directions". Por exemplo, se o destino de origem for um fragmento com o nome
SpecifyAmountFragment
, a classe gerada será chamadaSpecifyAmountFragmentDirections
.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á denominadaConfirmationAction
. Se a ação tiver argumentos sem umdefaultValue
, a classe de ação associada será usada 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á chamadaConfirmationFragmentArgs
. Use o métodofromBundle()
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 o delegado da 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 no exemplo a seguir:
Kotlin
val 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
extrair 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 uma das abordagens
abaixo para transmitir o Bundle
ao destino inicial:
- Se você estiver criando
NavHost
de forma programática, chameNavHostFragment.create(R.navigation.graph, args)
, em queargs
é oBundle
que contém seus dados. - Caso contrário, é possível definir argumentos de destino inicial chamando uma das
seguintes sobrecargas de
NavController.setGraph()
:- Use o ID do gráfico:
navController.setGraph(R.navigation.graph, args)
- Use o próprio gráfico:
navController.setGraph(navGraph, args)
- Use o ID do gráfico:
Para recuperar os dados no destino inicial, chame
Fragment.getArguments()
.
Considerações sobre o ProGuard
Se você estiver reduzindo seu código, vai precisar evitar que os nomes das 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.
- Use regras keepnames.
As subseções a seguir descrevem essas abordagens.
Usar anotações @Keep
O exemplo a seguir adiciona 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 recursos adicionais a seguir.
Exemplos
- NavigationBasicSample (em inglês)