La navigazione consente di collegare dati a un'operazione di navigazione definendo argomenti per una destinazione. Ad esempio, la destinazione di un profilo utente potrebbe richiedere un argomento User-ID per determinare quale utente visualizzare.
In generale, consigliamo vivamente di trasferire solo la quantità minima di dati tra le destinazioni. Ad esempio, per recuperare un oggetto, piuttosto che passare l'oggetto stesso, devi passare una chiave, poiché lo spazio totale per tutti gli stati salvati è limitato su Android. Se devi trasmettere grandi quantità di dati, utilizza una proprietà ViewModel
come descritto nella panoramica di ViewModel.
Definisci gli argomenti di destinazione
Per passare dati tra destinazioni, devi innanzitutto definire 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 può essere associato a un valore null e, se necessario, un valore predefinito.
- Fai clic su Aggiungi. Nota che l'argomento ora compare nell'elenco Argomenti nel riquadro Attributi.
- Successivamente, fai clic sull'azione corrispondente che ti porta a questa destinazione. Nel riquadro Attributi ora 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 nota che l'argomento è stato aggiunto alla destinazione che riceve l'argomento. Di seguito è riportato un esempio:
<fragment android:id="@+id/myFragment" > <argument android:name="myArg" app:argType="integer" android:defaultValue="0" /> </fragment>
Tipi di argomenti supportati
La libreria di navigazione supporta i seguenti tipi di argomenti:
Tipo | sintassi app:argType | Supporto dei valori predefiniti | Gestione in base ai percorsi | Null |
---|---|---|---|---|
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ì - "vero" o "falso" | Sì | No |
Stringa | app:argType="string" | Sì | Sì | Sì |
Riferimento alle risorse | app:argType="reference" | Sì: i valori predefiniti devono essere nel formato "@resourceType/resourceName" (ad es. "@style/myCustomStyle") o "0" | Sì | No |
Personalizzabile in parcelle | app:argType="<type>", dove <type> è il nome completo della classe Parcelable |
Supporta un valore predefinito di "@null". Non supporta altri valori predefiniti. | No | Sì |
Serializzabile personalizzato | app:argType="<type>", dove <type> è il nome completo della classe Serializable |
Supporta un valore predefinito di "@null". Non supporta altri valori predefiniti. | No | Sì |
Enum personalizzata | 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 valori nulli, puoi dichiarare un valore predefinito nullo utilizzando android:defaultValue="@null"
.
Route, link diretti e URI con i relativi argomenti possono essere analizzati dalle stringhe. Ciò non è possibile utilizzando tipi di dati personalizzati come Parcelables e Serializables come mostrato nella tabella precedente. Per trasferire dati complessi personalizzati, memorizza i dati altrove, ad esempio in un ViewModel o in un database, e trasmetti un identificatore solo durante la navigazione; quindi recupera i dati nella nuova località al termine della navigazione.
Quando scegli uno dei tipi personalizzati, viene visualizzata la finestra di dialogo Seleziona classe e ti chiede di scegliere la classe corrispondente per quel tipo. La scheda Progetto ti consente di scegliere un corso dal progetto corrente.
Puoi scegliere <inferred type> per fare in modo che la libreria di navigazione determini il tipo in base al valore fornito.
Puoi selezionare Array per indicare che l'argomento deve essere un array del valore Type selezionato. Nota:
- Gli array di enum e di riferimenti alle risorse non sono supportati.
- Gli array supportano valori con valori nulli, indipendentemente dal supporto per i valori con null del tipo sottostante. Ad esempio, l'uso di
app:argType="integer[]"
ti consente di utilizzareapp:nullable="true"
per indicare che il passaggio di un array nullo è accettabile. - Gli array supportano un singolo valore predefinito, "@null". Gli array non supportano altri valori predefiniti.
Override di un argomento di destinazione in un'azione
Gli argomenti e i valori predefiniti a livello di destinazione sono utilizzati da tutte le azioni che accedino alla destinazione. Se necessario, puoi eseguire l'override del 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 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 Navigazione ha un plug-in Gradle chiamato Safe Args che genera semplici classi di oggetti e builder per una navigazione sicura per tipo e l'accesso a qualsiasi argomento associato. L'utilizzo di Args sicuri è vivamente consigliato per la navigazione e il trasferimento dei dati, perché garantisce la sicurezza dei tipi.
Se non utilizzi Gradle, non puoi utilizzare il plug-in Safe Args. In questi casi, puoi utilizzare i bundle per trasmettere i dati direttamente.
Per aggiungere arg. sicuri
al tuo progetto, includi i seguenti classpath
nel file build.gradle
di primo livello:
Alla moda
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") } }
Devi inoltre applicare uno dei due plug-in disponibili.
Per generare un codice del linguaggio Java adatto a moduli Java o misti Java e Kotlin, aggiungi
questa riga nel file build.gradle
della tua app o del tuo modulo:
Alla moda
plugins { id 'androidx.navigation.safeargs' }
Kotlin
plugins { id("androidx.navigation.safeargs") }
In alternativa, per generare un codice Kotlin adatto ai moduli solo Kotlin, aggiungi:
Alla moda
plugins { id 'androidx.navigation.safeargs.kotlin' }
Kotlin
plugins { id("androidx.navigation.safeargs.kotlin") }
Devi avere android.useAndroidX=true
nel tuo
gradle.properties
file in base a
Migrazione ad AndroidX.
Dopo aver abilitato Args sicuri, il codice generato contiene i seguenti metodi e classi di sicurezza del tipo per ogni azione e 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 origine aggiunta alla parola "Indicazioni stradali". Ad esempio, se la destinazione di origine è un frammento denominato
SpecifyAmountFragment
, la classe generata si chiamaSpecifyAmountFragmentDirections
.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 è basato sull'azione. Ad esempio, se l'azione si chiama
confirmationAction,
, la classe si chiamaConfirmationAction
. Se l'azione contiene argomenti senzadefaultValue
, devi utilizzare la classe di azione associata per impostare il valore degli argomenti.Viene creata una classe per la destinazione ricevente. Il nome di questa classe è il nome della destinazione aggiunta alla parola "Args". Ad esempio, se il frammento di destinazione è denominato
ConfirmationFragment,
, la classe generata si chiamaConfirmationFragmentArgs
. Utilizza il metodofromBundle()
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 della destinazione ricevente, utilizza il metodo getArguments()
per recuperare il bundle e utilizzarne i contenuti. Quando si utilizzano le dipendenze -ktx
, gli utenti di Kotlin possono utilizzare anche il delegato della proprietà by navArgs()
per accedere agli 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 + ""); }
Usa Safe Args in un'azione globale
Quando utilizzi Args sicuri 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>
dispongono di metodi generati per accedere a tutte le azioni globali associate utilizzando gli stessi metodi descritti nella sezione precedente.
Trasferire dati tra destinazioni con oggetti Bundle
Se non utilizzi Gradle, puoi comunque passare argomenti tra le destinazioni utilizzando
oggetti Bundle
. Crea un oggetto Bundle
e trasmettilo 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 destinazione, utilizza il metodo getArguments()
per recuperare 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"));
Passa i dati alla destinazione di partenza
Puoi passare dati alla destinazione iniziale dell'app. Innanzitutto, devi creare esplicitamente
una Bundle
che contenga i dati. Quindi, utilizza uno dei seguenti approcci per passare Bundle
alla destinazione di partenza:
- Se stai creando il tuo
NavHost
in modo programmatico, chiamaNavHostFragment.create(R.navigation.graph, args)
, doveargs
è laBundle
che contiene i tuoi dati. - In caso contrario, puoi impostare gli argomenti 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 evitare che i nomi delle classi Parcelable
, Serializable
e Enum
vengano offuscati durante il processo di minimizzazione. Puoi farlo in due modi:
- Utilizza le annotazioni @Keep.
- Utilizza le regole keepnames.
Queste sottosezioni descrivono questi approcci.
Utilizzare le annotazioni @Keep
Nell'esempio seguente vengono aggiunte le annotazioni @Keep
alle definizioni delle classi dei 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 di 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.