La navigazione ti consente di associare dati a un'operazione di navigazione definendo gli argomenti per una destinazione. Ad esempio, una destinazione del profilo utente potrebbe richiedere un argomento ID utente per determinare quale utente visualizzare.
In generale, ti consigliamo vivamente di trasmettere solo la quantità minima di dati tra le destinazioni. Ad esempio, devi passare una chiave per recuperare un oggetto
piuttosto che l'oggetto stesso, poiché lo spazio totale per tutti gli stati salvati
è limitato su Android. Se devi trasmettere grandi quantità di dati, utilizza un ViewModel
come descritto nella panoramica di ViewModel.
Definisci gli argomenti di destinazione
Per passare i dati tra le destinazioni, definisci prima l'argomento aggiungendolo alla destinazione che lo riceve seguendo questi passaggi:
- Nell'Editor di navigazione, fai clic sulla destinazione che riceve l'argomento.
- Nel riquadro Attributi, fai clic su Aggiungi (+).
- Nella finestra Aggiungi link argomento visualizzata, inserisci il nome dell'argomento, il tipo di argomento, se l'argomento è nullable e un valore predefinito, se necessario.
- Fai clic su Aggiungi. Tieni presente che l'argomento ora viene visualizzato nell'elenco Argomenti nel riquadro Attributi.
- Poi, fai clic sull'azione corrispondente che ti indirizza a questa destinazione. Nel riquadro Attributi, dovresti vedere l'argomento appena aggiunto nella sezione Valori predefiniti dell'argomento.
Puoi anche vedere che l'argomento è stato aggiunto in XML. Fai clic sulla scheda Testo per passare alla visualizzazione XML e noterai che l'argomento è stato aggiunto alla destinazione che lo riceve. Un esempio è riportato di seguito:
<fragment android:id="@+id/myFragment" > <argument android:name="myArg" app:argType="integer" android:defaultValue="0" /> </fragment>
Tipi di argomenti supportati
La libreria Navigation supporta i seguenti tipi di argomenti:
Digitazione | Sintassi di app:argType | Supporto dei valori predefiniti | Gestito dalle route | Nullable |
---|---|---|---|---|
Numero intero | app:argType="integer" | Sì | Sì | No |
Mobile | app:argType="float" | Sì | Sì | No |
Lungo | app:argType="long" | Sì: i valori predefiniti devono sempre terminare con un suffisso "L" (ad es. "123L"). | Sì | No |
Booleano | app:argType="boolean" | Sì: "true" o "false" | Sì | No |
Stringa | app:argType="string" | Sì | Sì | Sì |
Riferimento alla risorsa | app:argType="reference" | Sì: i valori predefiniti devono essere nel formato "@resourceType/resourceName" (ad es. "@style/myCustomStyle") o "0" | Sì | No |
Custom Parcelable | app:argType="<type>", dove <type> è il nome completo della classe dell'Parcelable |
Supporta un valore predefinito di "@null". Non supporta altri valori predefiniti. | No | Sì |
Serializable personalizzato | app:argType="<type>", dove <type> è il nome completo della classe dell'Serializable |
Supporta un valore predefinito di "@null". Non supporta altri valori predefiniti. | No | Sì |
Enum personalizzato | app:argType="<type>", dove <type> è il nome completo dell'enum | Sì: i valori predefiniti devono corrispondere al nome non qualificato (ad es. "SUCCESS" per corrispondere a MyEnum.SUCCESS). | No | No |
Se un tipo di argomento supporta i valori null, puoi dichiarare un valore predefinito di
null utilizzando android:defaultValue="@null"
.
Le route, i link diretti e gli URI con i relativi argomenti possono essere analizzati dalle stringhe. Ciò non è possibile utilizzando tipi di dati personalizzati come Parcelable e Serializable, come mostrato nella tabella precedente. Per trasmettere dati complessi personalizzati, memorizzali altrove, ad esempio in un ViewModel o in un database, e passa solo un identificatore durante la navigazione. Recupera poi i dati nella nuova posizione al termine della navigazione.
Quando scegli uno dei tipi personalizzati, viene visualizzata la finestra di dialogo Seleziona corso, che ti chiede di scegliere il corso corrispondente per quel tipo. La scheda Progetto consente di scegliere un corso dal progetto corrente.
Puoi scegliere <inferred type> per consentire alla libreria di navigazione di determinare il tipo in base al valore fornito.
Puoi selezionare Array per indicare che l'argomento deve essere un array del valore Tipo selezionato. Nota:
- Gli array di enum e gli array di riferimenti alle risorse non sono supportati.
- Gli array supportano i valori nullable, indipendentemente dal supporto dei valori nullable del tipo sottostante. Ad esempio, l'utilizzo di
app:argType="integer[]"
ti consente di utilizzareapp:nullable="true"
per indicare che è accettabile passare un array null. - Gli array supportano un singolo valore predefinito, "@null". Le matrici non supportano nessun altro valore predefinito.
Sostituire un argomento di destinazione in un'azione
Gli argomenti e i valori predefiniti a livello di destinazione vengono utilizzati da tutte le azioni che indirizzano alla destinazione. Se necessario, puoi sostituire il valore predefinito di un argomento (o impostarne uno se non esiste già) definendo un argomento a livello di azione. Questo argomento deve avere lo stesso nome e lo stesso tipo dell'argomento dichiarato nella destinazione.
Il seguente XML dichiara un'azione con un argomento che sostituisce l'argomento a livello di destinazione dell'esempio precedente:
<action android:id="@+id/startMyFragment"
app:destination="@+id/myFragment">
<argument
android:name="myArg"
app:argType="integer"
android:defaultValue="1" />
</action>
Utilizza Safe Args per trasmettere dati con sicurezza del tipo
Il componente Navigation ha un plug-in Gradle chiamato Safe Args che genera classi di oggetti e builder semplici per la navigazione sicura e l'accesso a eventuali argomenti associati. Safe Args è vivamente consigliato per la navigazione e la trasmissione dei dati, in quanto garantisce la sicurezza del tipo.
Se non utilizzi Gradle, non puoi utilizzare il plug-in SafeArgs. In questi casi, puoi utilizzare i pacchetti per trasmettere direttamente i dati.
Per aggiungere Safe Args al progetto, includi il seguente classpath
nel file build.gradle
di primo livello:
Groovy
buildscript { repositories { google() } dependencies { def nav_version = "2.8.4" classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version" } }
Kotlin
buildscript { repositories { google() } dependencies { val nav_version = "2.8.4" classpath("androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version") } }
Devi anche applicare uno dei due plug-in disponibili.
Per generare codice in linguaggio Java adatto per moduli Java o misti Java e Kotlin, aggiungi
questa riga al file build.gradle
della tua app o del tuo modulo:
Groovy
plugins { id 'androidx.navigation.safeargs' }
Kotlin
plugins { id("androidx.navigation.safeargs") }
In alternativa, per generare codice Kotlin adatto per i moduli solo Kotlin, aggiungi:
Groovy
plugins { id 'androidx.navigation.safeargs.kotlin' }
Kotlin
plugins { id("androidx.navigation.safeargs.kotlin") }
Devi avere android.useAndroidX=true
nel
file gradle.properties
come da
Migrazione ad AndroidX.
Dopo aver attivato Safe Args, il codice generato contiene i seguenti metodi e classi di tipo sicuro per ogni azione, nonché per ogni destinazione di invio e ricezione.
Viene creata una classe per ogni destinazione da cui ha origine un'azione. Il nome di questa classe è il nome della destinazione di partenza seguito dalla parola "Indicazioni". Ad esempio, se la destinazione di origine è un frammento denominato
SpecifyAmountFragment
, la classe generata è chiamataSpecifyAmountFragmentDirections
.Questa classe ha un metodo per ogni azione definita nella destinazione di origine.
Per ogni azione utilizzata per passare l'argomento, viene creata una classe interna il cui nome si basa sull'azione. Ad esempio, se l'azione si chiama
confirmationAction,
, la classe si chiamaConfirmationAction
. Se la tua azione contiene argomenti senzadefaultValue
, utilizza la classe di azioni associata per impostare il valore degli argomenti.Viene creato un corso per la destinazione di ricezione. Il nome di questa classe è il nome della destinazione a cui è stata aggiunta la parola "Args". Ad esempio, se il frammento di destinazione è denominato
ConfirmationFragment,
, la classe generata èConfirmationFragmentArgs
. Utilizza ilfromBundle()
metodo di questa classe per recuperare gli argomenti.
L'esempio seguente mostra come utilizzare questi metodi per impostare un argomento e passarlo al metodo 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); }
Nel codice per la destinazione di ricezione, utilizza il metodo getArguments()
per recuperare il pacchetto e utilizzarne i contenuti. Quando utilizzi le dipendenze -ktx
,
gli utenti di Kotlin possono anche utilizzare il delegato della proprietà by navArgs()
per accedere
gli argomenti.
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 + ""); }
Utilizzare Safe Args con un'azione globale
Quando utilizzi Safe Args con un'azione globale, devi fornire un valore android:id
per l'elemento <navigation>
principale, come mostrato nell'esempio seguente:
<?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>
La navigazione genera una classe Directions
per l'elemento <navigation>
basata sul valore android:id
. Ad esempio, se hai un elemento <navigation>
con android:id=@+id/main_nav
, la classe generata si chiama MainNavDirections
. Tutte le destinazioni all'interno dell'elemento <navigation>
hanno metodi generati per accedere a tutte le azioni globali associate utilizzando gli stessi metodi descritti nella sezione precedente.
Passare dati tra destinazioni con oggetti Bundle
Se non utilizzi Gradle, puoi comunque passare gli argomenti tra le destinazioni utilizzando gli oggetti Bundle
. Crea un oggetto Bundle
e passalo alla destinazione
utilizzando navigate()
, come nell'esempio seguente:
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);
Nel codice della destinazione di ricezione, utilizza il metodo getArguments()
per recuperare il Bundle
e utilizzarne i contenuti:
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"));
Passare i dati alla destinazione iniziale
Puoi passare i dati alla destinazione iniziale dell'app. Innanzitutto, devi
costruire esplicitamente un Bundle
che contenga i dati. Poi, utilizza uno dei seguenti metodi per passare Bundle
alla destinazione iniziale:
- Se crei
NavHost
tramite programmazione, chiamaNavHostFragment.create(R.navigation.graph, args)
, doveargs
èBundle
che contiene i tuoi dati. - In caso contrario, puoi impostare gli argomenti della destinazione iniziale chiamando uno dei seguenti sovraccarichi di
NavController.setGraph()
:- Utilizza l'ID del grafico:
navController.setGraph(R.navigation.graph, args)
- Utilizza il grafico stesso:
navController.setGraph(navGraph, args)
- Utilizza l'ID del grafico:
Per recuperare i dati nella destinazione iniziale, chiama
Fragment.getArguments()
.
Considerazioni su ProGuard
Se riduci il codice, devi impedire che i nomi delle classi Parcelable
,
Serializable
e Enum
vengano offuscati durante il processo di minimizzazione. Puoi eseguire questa operazione in due modi:
- Utilizza le annotazioni @Keep.
- Utilizza le regole keepnames.
Le sottosezioni seguenti descrivono questi approcci.
Utilizzare le annotazioni @Keep
L'esempio seguente aggiunge annotazioni @Keep
alle definizioni delle classi di modelli:
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 { ... }
Utilizzare le regole keepnames
Puoi anche aggiungere regole keepnames
al file proguard-rules.pro
, come mostrato
nell'esempio seguente:
proguard-rules.pro
...
-keepnames class com.path.to.your.ParcelableArg
-keepnames class com.path.to.your.SerializableArg
-keepnames class com.path.to.your.EnumArg
...
Risorse aggiuntive
Per scoprire di più sulla navigazione, consulta le seguenti risorse aggiuntive.