Trasmettere dati tra destinazioni

La navigazione ti consente di collegare dati a un'operazione di navigazione definendo argomenti per una destinazione. Ad esempio, la destinazione di un profilo utente potrebbe accettare un ID utente per determinare quale utente visualizzare.

In generale, dovresti preferire vivamente il trasferimento solo della quantità minima di dati. tra le destinazioni. Ad esempio, devi passare una chiave per recuperare un oggetto anziché passare l'oggetto stesso, come spazio totale per tutti gli stati salvati. è limitato su Android. Se devi trasferire grandi quantità di dati, utilizza un ViewModel come descritto in Panoramica di ViewModel.

Definisci gli argomenti di destinazione

Per passare i dati tra le destinazioni, devi prima definire l'argomento aggiungendolo al metodo che la riceve:

  1. Nell'Editor di navigazione: fai clic sulla destinazione che riceve l'argomento.
  2. Nel riquadro Attributi, fai clic su Aggiungi (+).
  3. Nella finestra Aggiungi link argomento che viene visualizzata, inserisci il nome dell'argomento. tipo di argomento, se l'argomento è nullo e un valore predefinito, se necessaria.
  4. Fai clic su Aggiungi. Tieni presente che l'argomento ora appare nella sezione Argomenti nel riquadro Attributi.
  5. Fai clic sull'azione corrispondente che ti porta a questa destinazione. Nel riquadro Attributi, dovresti vedere l'argomento appena aggiunto. nella sezione Valori predefiniti dell'argomento.
  6. 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 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 per i valori predefiniti Gestione tramite route Nullable
Numero intero app:argType="integer" No
Mobile app:argType="float" No
Lungo app:argType="long" Sì. I valori predefiniti devono sempre terminare con una "L" (ad es. "123L"). No
Booleano app:argType="boolean" Sì - "true" o "false" No
Stringa app:argType="string"
Riferimento alle risorse app:argType="reference" Sì. I valori predefiniti devono essere nel formato "@resourceType/resourceName" (ad es. "@style/myCustomStyle") o "0" No
Pacchettizzazione personalizzata app:argType="<type>", dove <type> è il nome completo del corso Parcelable Supporta il valore predefinito "@null". Non supporta altri valori predefiniti. No
Serie serializzabile personalizzata app:argType="<type>", dove <type> è il nome completo del corso Serializable Supporta il valore predefinito "@null". Non supporta altri valori predefiniti. No
Enum personalizzato app:argType="<type>", dove <type> è il nome completo dell'enumerazione 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 null, puoi dichiarare un valore predefinito nullo utilizzando android:defaultValue="@null".

Route, link diretti e URI con i relativi argomenti possono essere analizzati dalle stringhe. Questa operazione non è possibile quando si utilizzano tipi di dati personalizzati, come Parcelables e Serializzabili come indicato nella tabella precedente. Per trasferire dati complessi personalizzati, archivia i dati altrove, ad esempio in un ViewModel o un database e trasmette solo un identificatore durante la navigazione; quindi recupera i dati nella nuova posizione al termine della navigazione.

Quando scegli uno dei tipi personalizzati, viene visualizzata la finestra di dialogo Seleziona corso. ti chiede di scegliere la classe corrispondente per quel tipo. La scheda Progetto consente di scegliere un corso dal progetto corrente.

Puoi scegliere <tipo dedotto> per avere la Libreria di navigazione determinare il tipo in base al valore fornito.

Puoi selezionare Array per indicare che l'argomento deve essere un array del il valore Type selezionato. Nota:

  • Gli array di enum e di riferimenti alle risorse non sono supportati.
  • Gli array supportano valori nulli, a prescindere dal supporto di questi valori. del tipo sottostante. Ad esempio, utilizzando app:argType="integer[]" ti consente di usare app:nullable="true" per indicano che è accettabile passare un array nullo.
  • Gli array supportano un singolo valore predefinito, "@null". Gli array non supportano nessuna l'altro valore predefinito.
di Gemini Advanced.

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 raggiungere la destinazione. Se necessario, puoi eseguire l'override del valore predefinito (o impostane uno se non esiste già) definendo un argomento livello di azione. Questo argomento deve avere lo stesso nome e tipo dell'argomento. dichiarate nella destinazione.

Il seguente codice XML dichiara un'azione con un argomento che sostituisce la l'argomento destination-level dell'esempio precedente:

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

Usa Safe Args per trasferire dati con la sicurezza dei tipi

Il componente Navigazione ha un plug-in Gradle chiamato Safe Args che genera semplici classi di oggetti e builder per una navigazione sicura del tipo e l'accesso a argomenti associati. Safe Args è vivamente consigliato per navigare trasmettere dati, perché garantisce la sicurezza del tipo.

Se non usi Gradle, non puoi usare l'app Plug-in Args. In questi casi, puoi utilizzare i bundle per trasmessi.

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 attivato Safe Args, il codice generato contiene quanto segue digitare classi e metodi sicuri per ogni azione così come con ogni invio destinazione.

  • Viene creata una classe per ogni destinazione in cui ha origine un'azione. Il nome di questa classe è il nome della destinazione di origine seguito dal parola "Indicazioni stradali". Ad esempio, se la destinazione di origine è un frammento denominata SpecifyAmountFragment, la classe generata si chiama SpecifyAmountFragmentDirections.

    Questa classe ha un metodo per ogni azione definita nell'elemento destinazione.

  • Per ogni azione utilizzata per passare l'argomento, viene creata una classe interna la cui nome si basa sull'azione. Ad esempio, se l'azione viene chiamata confirmationAction, il corso si chiama ConfirmationAction. Se le tue contiene argomenti senza un valore defaultValue, viene utilizzata una classe di azioni associata per impostare il valore degli argomenti.

  • Viene creato un corso per la destinazione di destinazione. Il nome di questo corso è il nome della destinazione seguito dalla parola "Args". Ad esempio, se il frammento di destinazione è denominato ConfirmationFragment, il valore si chiama ConfirmationFragmentArgs. Utilizza fromBundle() di questo corso per recuperare gli argomenti.

L'esempio seguente mostra come utilizzare questi metodi per impostare un argomento passala a 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 usarne i contenuti. Quando utilizzi le dipendenze -ktx, Gli utenti Kotlin possono anche utilizzare il delegato della proprietà by navArgs() per accedere 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 + "");
}

Utilizza 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 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>, in base al valore android:id. Ad esempio, se hai un <navigation> con android:id=@+id/main_nav, la classe generata viene chiamata MainNavDirections. Tutte le destinazioni all'interno dell'elemento <navigation> hanno generati per accedere a tutte le azioni globali associate usando lo stesso come descritto nella sezione precedente.

Trasmettere dati tra destinazioni con gli oggetti Bundle

Se non utilizzi Gradle, puoi comunque trasferire argomenti tra le destinazioni usando Bundle oggetti. 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 recupera Bundle e utilizza i suoi 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 trasmettere i dati alla destinazione di partenza della tua app. Innanzitutto, devi esplicitamente creare una Bundle che contenga i dati. Dopodiché, utilizza una delle seguenti opzioni approcci per passare Bundle alla destinazione di partenza:

Per recuperare i dati nella destinazione di partenza, chiama Fragment.getArguments()

Considerazioni su ProGuard

Se stai restringendo il codice, devi evitare che Parcelable, I nomi delle classi Serializable e Enum non siano offuscati nell'ambito della processo di minimizzazione. Puoi farlo in due modi:

  • Utilizza le annotazioni @Keep.
  • Utilizza le regole keepnames.

Le seguenti sottosezioni descrivono questi approcci.

Utilizzare le annotazioni @Keep

Nell'esempio seguente vengono aggiunte le annotazioni @Keep alle definizioni delle classi del modello:

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 { ... }

Utilizza le regole keepnames

Puoi anche aggiungere keepnames regole al tuo file proguard-rules.pro, come mostrato nel seguente esempio:

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 saperne di più sulla navigazione, consulta le seguenti risorse risorse aggiuntive.

Campioni

Codelab

Video