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:
- 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.
- 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.
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 | 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 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 | 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. Não é possível fazer isso usando tipos de dados personalizados, como Parcelables e Serializables, conforme visto na tabela acima. 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, usar
app:argType="integer[]"
permite que você useapp:nullable="true"
para indicar que transmitir 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 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:
Groovy
buildscript { repositories { google() } dependencies { def nav_version = "2.5.3" classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version" } }
Kotlin
buildscript { repositories { google() } dependencies { val nav_version = "2.5.3" 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 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 deSpecifyAmountFragmentDirections
.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 contiver argumentos semdefaultValue
, 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á 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 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
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 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. Depois,
use um dos métodos a seguir para transmitir o Bundle
para o destino inicial:
- Se você estiver criando seu
NavHost
programaticamente, chameNavHostFragment.create(R.navigation.graph, args)
, em que args é oBundle
que mantém seus dados. - Caso contrário, você pode definir argumentos de destino inicial chamando uma das
seguintes sobrecargas de
NavController.setGraph()
:- Usando o ID do gráfico:
navController.setGraph(R.navigation.graph, args)
- Usando o próprio gráfico:
navController.setGraph(navGraph, args)
- Usando 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,
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 recursos adicionais a seguir.