Bei der Navigation können Sie Daten an einen Navigationsvorgang anhängen, indem Sie Argumente für ein Ziel definieren. Ein Nutzerprofilziel kann beispielsweise ein Nutzer-ID-Argument annehmen, um zu bestimmen, welcher Nutzer angezeigt werden soll.
Im Allgemeinen sollten Sie nur die minimale Datenmenge zwischen Zielen übergeben. Sie sollten beispielsweise einen Schlüssel zum Abrufen eines Objekts übergeben, anstatt das Objekt selbst, da der Gesamtspeicherplatz für alle gespeicherten Status auf Android begrenzt ist. Wenn Sie große Datenmengen übergeben müssen, verwenden Sie ein ViewModel
, wie in der Übersicht über das ViewModel beschrieben.
Zielargumente definieren
Wenn Sie Daten zwischen Zielen übergeben möchten, müssen Sie zuerst das Argument definieren. Fügen Sie es dazu dem Ziel hinzu, das es empfängt. Gehen Sie dazu so vor:
- Klicken Sie im Navigationseditor auf das Ziel, an das das Argument gesendet werden soll.
- Klicken Sie im Bereich Attribute auf Hinzufügen (+).
- Geben Sie im Fenster Argumentverknüpfung hinzufügen den Namen, den Argumenttyp, ob das Argument nullable ist, und bei Bedarf einen Standardwert ein.
- Klicken Sie auf Hinzufügen. Das Argument wird jetzt in der Liste Argumente im Bereich Attribute angezeigt.
- Klicken Sie als Nächstes auf die entsprechende Aktion, über die Sie zu diesem Ziel gelangen. Im Bereich Attribute sollte das neu hinzugefügte Argument jetzt im Abschnitt Standardwerte für Argumente angezeigt werden.
Außerdem sehen Sie, dass das Argument in XML hinzugefügt wurde. Klicken Sie auf den Tab Text, um zur XML-Ansicht zu wechseln. Sie sehen, dass das Argument dem Ziel hinzugefügt wurde, an das es gesendet wird. Hier ein Beispiel:
<fragment android:id="@+id/myFragment" > <argument android:name="myArg" app:argType="integer" android:defaultValue="0" /> </fragment>
Unterstützte Argumenttypen
Die Navigationsbibliothek unterstützt die folgenden Argumenttypen:
Eingeben | Syntax von „app:argType“ | Unterstützung für Standardwerte | Von Routen verarbeitet | Nullable |
---|---|---|---|---|
Ganzzahl | app:argType="integer" | Ja | Ja | Nein |
Frei schwebend | app:argType="float" | Ja | Ja | Nein |
Lang | app:argType="long" | Ja. Standardwerte müssen immer auf „L“ enden (z. B. „123L“). | Ja | Nein |
Boolesch | app:argType="boolean" | Ja – „wahr“ oder „falsch“ | Ja | Nein |
String | app:argType="string" | Ja | Ja | Ja |
Ressourcenreferenz | app:argType="reference" | Ja – Standardwerte müssen das Format „@resourceType/resourceName“ (z. B. „@style/myCustomStyle“) oder „0“ haben. | Ja | Nein |
Benutzerdefiniertes Parcelable | app:argType="<type>", wobei <type> der vollständig qualifizierte Klassenname der Parcelable ist |
Unterstützt den Standardwert „@null“. Andere Standardwerte werden nicht unterstützt. | Nein | Ja |
Benutzerdefiniert serialisierbar | app:argType="<type>", wobei <type> der vollständig qualifizierte Klassenname der Serializable ist |
Unterstützt den Standardwert „@null“. Andere Standardwerte werden nicht unterstützt. | Nein | Ja |
Benutzerdefiniertes Enum | app:argType="<type>", wobei <type> der voll qualifizierte Name des Enumerationstyps ist | Ja. Standardwerte müssen mit dem einfachen Namen übereinstimmen, z. B. „ERFOLG“, um mit „MyEnum.ERFOLG“ übereinzustimmen. | Nein | Nein |
Wenn ein Argumenttyp Nullwerte unterstützt, können Sie mit android:defaultValue="@null"
einen Standardwert von „null“ angeben.
Routen, Deeplinks und URIs mit ihren Argumenten können aus Strings geparst werden. Das ist mit benutzerdefinierten Datentypen wie Parcelables und Serializables nicht möglich, wie in der vorherigen Tabelle dargestellt. Wenn Sie benutzerdefinierte komplexe Daten übergeben möchten, speichern Sie die Daten an einem anderen Ort, z. B. in einem ViewModel oder einer Datenbank, und übergeben Sie während der Navigation nur eine Kennung. Rufen Sie die Daten dann am neuen Speicherort ab, nachdem die Navigation abgeschlossen ist.
Wenn Sie einen der benutzerdefinierten Typen auswählen, wird das Dialogfeld Klasse auswählen angezeigt. Dort werden Sie aufgefordert, die entsprechende Klasse für diesen Typ auszuwählen. Auf dem Tab Projekt können Sie einen Kurs aus Ihrem aktuellen Projekt auswählen.
Sie können <inferred type> auswählen, damit die Navigationsbibliothek den Typ anhand des angegebenen Werts bestimmt.
Wenn Sie Array aktivieren, geben Sie an, dass das Argument ein Array des ausgewählten Typs sein soll. Beachten Sie Folgendes:
- Arrays von Enumerationen und Arrays von Ressourcenreferenzen werden nicht unterstützt.
- Arrays unterstützen Werte mit Nullen unabhängig davon, ob der zugrunde liegende Typ Nullwerte unterstützt. Wenn Sie beispielsweise
app:argType="integer[]"
verwenden, können Sie mitapp:nullable="true"
angeben, dass das Übergeben eines Null-Arrays zulässig ist. - Arrays unterstützen einen einzelnen Standardwert: „@null“. Für Arrays wird kein anderer Standardwert unterstützt.
Zielargument in einer Aktion überschreiben
Argumente und Standardwerte auf Zielebene werden von allen Aktionen verwendet, die zum Ziel führen. Bei Bedarf können Sie den Standardwert eines Arguments überschreiben (oder einen festlegen, falls noch keiner vorhanden ist), indem Sie ein Argument auf Aktionsebene definieren. Dieses Argument muss denselben Namen und Typ haben wie das im Ziel deklarierte Argument.
In der folgenden XML-Datei wird eine Aktion mit einem Argument deklariert, das das Argument auf Zielebene aus dem vorherigen Beispiel überschreibt:
<action android:id="@+id/startMyFragment"
app:destination="@+id/myFragment">
<argument
android:name="myArg"
app:argType="integer"
android:defaultValue="1" />
</action>
Safe Args verwenden, um Daten mit Typsicherheit zu übergeben
Die Navigationskomponente hat ein Gradle-Plug-in namens Safe Args, das einfache Objekt- und Builder-Klassen für die typsichere Navigation und den Zugriff auf alle zugehörigen Argumente generiert. Safe Args wird für die Navigation und Weitergabe von Daten dringend empfohlen, da es für Typsicherheit sorgt.
Wenn Sie Gradle nicht verwenden, können Sie das SafeArgs-Plug-in nicht verwenden. In diesen Fällen können Sie Bundles verwenden, um Daten direkt zu übergeben.
Wenn Sie Ihrem Projekt Safe Args hinzufügen möchten, fügen Sie der build.gradle
-Datei auf oberster Ebene die folgende classpath
hinzu:
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") } }
Außerdem müssen Sie eines der beiden verfügbaren Plug-ins anwenden.
Wenn Sie Java-Code generieren möchten, der für Java- oder gemischte Java- und Kotlin-Module geeignet ist, fügen Sie der build.gradle
-Datei Ihrer App oder Ihres Moduls diese Zeile hinzu:
Groovy
plugins { id 'androidx.navigation.safeargs' }
Kotlin
plugins { id("androidx.navigation.safeargs") }
Alternativ können Sie Kotlin-Code generieren, der für reine Kotlin-Module geeignet ist. Fügen Sie dazu Folgendes hinzu:
Groovy
plugins { id 'androidx.navigation.safeargs.kotlin' }
Kotlin
plugins { id("androidx.navigation.safeargs.kotlin") }
Gemäß der Anleitung Zu AndroidX migrieren muss android.useAndroidX=true
in Ihrer gradle.properties
-Datei enthalten sein.
Nachdem Sie sichere Argumente aktiviert haben, enthält der generierte Code für jede Aktion sowie für jedes Sende- und Empfangsziel die folgenden sicheren Klassen und Methoden.
Für jedes Ziel, von dem eine Aktion ausgeht, wird eine Klasse erstellt. Der Name dieser Klasse ist der Name des Startziels, gefolgt vom Wort „Wegbeschreibung“. Wenn das ursprüngliche Ziel beispielsweise ein Fragment mit dem Namen
SpecifyAmountFragment
ist, heißt die generierte KlasseSpecifyAmountFragmentDirections
.Diese Klasse hat eine Methode für jede Aktion, die im ursprünglichen Ziel definiert ist.
Für jede Aktion, mit der das Argument übergeben wird, wird eine innere Klasse erstellt, deren Name auf der Aktion basiert. Wenn die Aktion beispielsweise
confirmationAction,
heißt, hat die Klasse den NamenConfirmationAction
. Wenn Ihre Aktion Argumente ohnedefaultValue
enthält, verwenden Sie die zugehörige Aktionsklasse, um den Wert der Argumente festzulegen.Für das Ziel wird eine Klasse erstellt. Der Name dieser Klasse ist der Name des Ziels, gefolgt vom Wort „Args“. Wenn das Zielfragment beispielsweise
ConfirmationFragment,
heißt, wird die generierte KlasseConfirmationFragmentArgs
genannt. Verwenden Sie die MethodefromBundle()
dieser Klasse, um die Argumente abzurufen.
Im folgenden Beispiel wird gezeigt, wie Sie mit diesen Methoden ein Argument festlegen und an die Methode navigate()
übergeben:
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); }
Verwende im Code für das Ziel die Methode getArguments()
, um das Bundle abzurufen und seinen Inhalt zu verwenden. Wenn Sie -ktx
-Abhängigkeiten verwenden, können Kotlin-Nutzer auch den by navArgs()
-Property-Delegate verwenden, um auf Argumente zuzugreifen.
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 + ""); }
Safe Args mit einer globalen Aktion verwenden
Wenn du Safe Args mit einer globalen Aktion verwendest, musst du einen android:id
-Wert für das Stammelement <navigation>
angeben, wie im folgenden Beispiel gezeigt:
<?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>
Bei der Navigation wird für das <navigation>
-Element eine Directions
-Klasse generiert, die auf dem android:id
-Wert basiert. Wenn Sie beispielsweise ein <navigation>
-Element mit android:id=@+id/main_nav
haben, heißt die generierte Klasse MainNavDirections
. Für alle Ziele im <navigation>
-Element wurden Methoden zum Zugriff auf alle zugehörigen globalen Aktionen generiert. Dabei wurden die im vorherigen Abschnitt beschriebenen Methoden verwendet.
Daten mit Bundle-Objekten zwischen Zielen übergeben
Wenn Sie Gradle nicht verwenden, können Sie Argumente auch mithilfe von Bundle
-Objekten zwischen Zielen übergeben. Erstellen Sie ein Bundle
-Objekt und übergeben Sie es wie im folgenden Beispiel mit navigate()
an das Ziel:
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);
Verwende im Code des Empfängers die Methode getArguments()
, um die Bundle
abzurufen und ihren Inhalt zu verwenden:
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"));
Daten an das Startziel übergeben
Sie können Daten an das Startziel Ihrer App übergeben. Zuerst müssen Sie explizit eine Bundle
erstellen, die die Daten enthält. Verwenden Sie dann eine der folgenden Methoden, um die Bundle
an das Startziel weiterzuleiten:
- Wenn Sie Ihre
NavHost
programmatisch erstellen, rufen SieNavHostFragment.create(R.navigation.graph, args)
auf. Dabei istargs
dieBundle
, die Ihre Daten enthält. - Andernfalls können Sie Startziel-Argumente festlegen, indem Sie eine der folgenden Überladungen von
NavController.setGraph()
aufrufen:- Verwenden Sie die ID des Diagramms:
navController.setGraph(R.navigation.graph, args)
. - Über das Diagramm selbst:
navController.setGraph(navGraph, args)
- Verwenden Sie die ID des Diagramms:
Rufen Sie Fragment.getArguments()
auf, um die Daten im Startziel abzurufen.
Hinweise zu ProGuard
Wenn Sie Ihren Code verkleinern, müssen Sie verhindern, dass die Klassennamen Parcelable
, Serializable
und Enum
im Rahmen des Minimierungsprozesses verschleiert werden. Dafür stehen Ihnen zwei Möglichkeiten zur Verfügung:
- Verwenden Sie @Keep-Anmerkungen.
- Verwenden Sie Regeln für die Beibehaltung von Namen.
In den folgenden Unterabschnitten werden diese Ansätze beschrieben.
Anmerkungen von @Google Notizen verwenden
Im folgenden Beispiel werden den Modellklassendefinitionen @Keep
-Anmerkungen hinzugefügt:
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 { ... }
Regeln für die Beibehaltung von Namen verwenden
Sie können Ihrer proguard-rules.pro
-Datei auch keepnames
-Regeln hinzufügen, wie im folgenden Beispiel gezeigt:
proguard-rules.pro
...
-keepnames class com.path.to.your.ParcelableArg
-keepnames class com.path.to.your.SerializableArg
-keepnames class com.path.to.your.EnumArg
...
Weitere Informationen
Weitere Informationen zur Navigation finden Sie in den folgenden zusätzlichen Ressourcen.