Mit 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 verwenden, um zu bestimmen, welcher Nutzer angezeigt werden soll.
Im Allgemeinen ist es empfehlenswert, nur die minimale Datenmenge zwischen Zielen zu übergeben. Beispielsweise sollten Sie anstelle des Objekts selbst einen Schlüssel zum Abrufen eines Objekts übergeben, da der Gesamtspeicherplatz für alle gespeicherten Status unter Android begrenzt ist. Wenn Sie große Datenmengen übergeben müssen, sollten Sie einen ViewModel
verwenden, wie unter ViewModel – Übersicht beschrieben.
Zielargumente definieren
Definieren Sie zum Übergeben von Daten zwischen Zielen zuerst das Argument. Dazu fügen Sie es dem Ziel hinzu, das die Daten empfängt. Gehen Sie dazu so vor:
- Klicken Sie im Navigationseditor auf das Ziel, das das Argument empfängt.
- Klicken Sie im Bereich Attribute auf Hinzufügen (+).
- Geben Sie im angezeigten Fenster Argument-Link hinzufügen den Namen des Arguments, den Argumenttyp, ob für das Argument Nullwerte zulässig sind, sowie bei Bedarf einen Standardwert ein.
- Klicken Sie auf Hinzufügen. Das Argument wird jetzt im Bereich Attribute in der Liste Argumente angezeigt.
- Klicken Sie dann auf die entsprechende Aktion, die Sie zu diesem Ziel führt. Im Bereich Attribute sollte jetzt das neu hinzugefügte Argument im Abschnitt Standardwerte für Argumente angezeigt werden.
Sie können auch sehen, dass das Argument in XML hinzugefügt wurde. Klicken Sie auf den Tab Text, um zur XML-Ansicht zu wechseln. Sie sehen, dass Ihr Argument dem Ziel hinzugefügt wurde, das das Argument empfängt. 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:
Typ | Syntax: app:argType | Unterstützung von Standardwerten | Von Routen verarbeitet | Nullwerte zulässig |
---|---|---|---|---|
Ganzzahl | app:argType="integer" | Ja | Ja | Nein |
Frei schwebend | app:argType="Gleitkommazahl" | Ja | Ja | Nein |
Lang | app:argType="long" | Ja. Standardwerte müssen immer mit einem "L"-Suffix 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 |
Individuelle Paketierbarkeit | app:argType="<type>", wobei <type> der voll qualifizierte Klassenname von Parcelable ist. |
Unterstützt den Standardwert „@null“. Unterstützt keine anderen Standardwerte. | Nein | Ja |
Benutzerdefiniertes Serialisierbar | app:argType="<type>", wobei <type> der voll qualifizierte Klassenname von Serializable ist. |
Unterstützt den Standardwert „@null“. Unterstützt keine anderen Standardwerte. | Nein | Ja |
Benutzerdefinierte Aufzählung | app:argType="<type>", wobei <type> der voll qualifizierte Name der Enum ist | Ja. Standardwerte müssen mit dem unqualifizierten Namen übereinstimmen (z. B. "SUCCESS" für MyEnum.SUCCESS). | Nein | Nein |
Wenn ein Argumenttyp Nullwerte unterstützt, können Sie mit android:defaultValue="@null"
den Standardwert null deklarieren.
Routen, Deeplinks und URIs mit ihren Argumenten können über Strings geparst werden. Bei Verwendung benutzerdefinierter Datentypen wie „Paraelables“ und „Serializables“, wie in der vorherigen Tabelle dargestellt, ist dies nicht möglich. Um benutzerdefinierte komplexe Daten zu umgehen, speichern Sie die Daten an einem anderen Ort, z. B. in einem ViewModel oder in einer Datenbank, und geben Sie nur während der Navigation eine ID weiter. Rufen Sie dann die Daten am neuen Ort ab, nachdem die Navigation abgeschlossen ist.
Wenn Sie einen der benutzerdefinierten Typen auswählen, wird das Dialogfeld Klasse auswählen angezeigt und Sie werden aufgefordert, die entsprechende Klasse für diesen Typ auszuwählen. Auf dem Tab Projekt können Sie eine Klasse aus Ihrem aktuellen Projekt auswählen.
Wenn Sie <inferred type> auswählen, wird der Typ von der Navigationsbibliothek anhand des angegebenen Werts bestimmt.
Sie können Array aktivieren, um anzugeben, dass das Argument ein Array des ausgewählten Typ-Werts sein soll. Beachten Sie Folgendes:
- Arrays von Enums und Arrays von Ressourcenverweisen werden nicht unterstützt.
- Arrays unterstützen Nullwerte, unabhängig davon, ob Nullwerte des zugrunde liegenden Typs unterstützt werden. Bei Verwendung von
app:argType="integer[]"
können Sie beispielsweiseapp:nullable="true"
verwenden, um anzugeben, dass die Übergabe eines Nullarrays akzeptabel ist. - Arrays unterstützen den einzelnen Standardwert „@null“. Arrays unterstützen keinen anderen Standardwert.
Zielargument in einer Aktion überschreiben
Argumente und Standardwerte auf Zielebene werden von allen Aktionen verwendet, mit denen zum Ziel navigiert wird. Bei Bedarf können Sie den Standardwert eines Arguments überschreiben (oder einen Wert festlegen, falls noch keiner vorhanden ist), indem Sie ein Argument auf Aktionsebene definieren. Dieses Argument muss denselben Namen und Typ wie das im Ziel deklarierte Argument haben.
Der folgende XML-Code deklariert eine Aktion mit einem Argument, 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 zum Übergeben von Daten mit Typsicherheit verwenden
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 zugehörige Argumente generiert. Safe Args wird zum Navigieren und Übergeben von Daten dringend empfohlen, da es die Typsicherheit gewährleistet.
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.
Um sichere Argumente hinzuzufügen
fügen Sie folgendes classpath
in Ihre übergeordnete build.gradle
-Datei ein:
Cool
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") } }
Sie müssen außerdem eines der beiden verfügbaren Plug-ins anwenden.
Um für Java oder gemischte Java- und Kotlin-Module den Java-Sprachcode zu generieren,
diese Zeile in die build.gradle
-Datei Ihrer App oder Ihres Moduls ein:
Cool
plugins { id 'androidx.navigation.safeargs' }
Kotlin
plugins { id("androidx.navigation.safeargs") }
Alternativ können Sie folgenden Code hinzufügen, um Kotlin-Code zu generieren, der für reine Kotlin-Module geeignet ist:
Cool
plugins { id 'androidx.navigation.safeargs.kotlin' }
Kotlin
plugins { id("androidx.navigation.safeargs.kotlin") }
android.useAndroidX=true
muss in deinem
gradle.properties
Datei gemäß
Zu AndroidX migrieren
Nachdem Sie Safe Args aktiviert haben, enthält Ihr generierter Code für jede Aktion sowie für jedes Sende- und Empfangsziel die folgenden typsicheren Klassen und Methoden.
Für jedes Ziel, von dem eine Aktion ausgeht, wird eine Klasse erstellt. Der Name dieser Klasse ist der Name des Ausgangsorts, an den das Wort „Route“ angehängt wird. 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, die zum Übergeben des Arguments verwendet 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.Eine Klasse für das Empfängerziel wird erstellt. Der Name dieser Klasse ist der Name des Ziels, an den das Wort „Args“ angehängt wird. Lautet das Zielfragment beispielsweise
ConfirmationFragment,
, heißt die generierte KlasseConfirmationFragmentArgs
. 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); }
Verwenden Sie im Code für das empfangende Ziel die Methode getArguments()
, um das Bundle abzurufen und seinen Inhalt zu verwenden. Bei Verwendung der -ktx
-Abhängigkeiten können Kotlin-Nutzer auch den by navArgs()
-Attribut-Delegaten 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 + ""); }
Sichere Argumente mit globaler Aktion verwenden
Wenn Sie Safe Args mit einer globalen Aktion verwenden, müssen Sie 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>
Die Navigation generiert eine Directions
-Klasse für das Element <navigation>
, die auf dem Wert android:id
basiert. Wenn Sie beispielsweise ein <navigation>
-Element mit android:id=@+id/main_nav
haben, heißt die generierte Klasse MainNavDirections
. Alle Ziele im <navigation>
-Element haben generierte Methoden, um mit denselben Methoden wie im vorherigen Abschnitt beschrieben auf alle zugehörigen globalen Aktionen zuzugreifen.
Daten mit Bundle-Objekten zwischen Zielen übergeben
Auch wenn Sie Gradle nicht verwenden, können Sie Argumente zwischen Zielen mit Bundle
-Objekten übergeben. Erstellen Sie ein Bundle
-Objekt und übergeben Sie es mithilfe von 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);
Verwenden Sie im Code des Empfängerziels die Methode getArguments()
, um Bundle
abzurufen und seinen 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 einen der folgenden Ansätze, um Bundle
an das Startziel zu übergeben:
- Wenn Sie die
NavHost
programmatisch erstellen, rufen SieNavHostFragment.create(R.navigation.graph, args)
auf, wobeiargs
derBundle
ist, der Ihre Daten enthält. - Andernfalls können Sie Startzielargumente festlegen, indem Sie eine der folgenden Überlastungen von
NavController.setGraph()
aufrufen:- Verwenden Sie die ID der Grafik:
navController.setGraph(R.navigation.graph, args)
- Die Grafik selbst verwenden:
navController.setGraph(navGraph, args)
- Verwenden Sie die ID der Grafik:
Rufen Sie Fragment.getArguments()
auf, um die Daten im Startziel abzurufen.
Überlegungen zu ProGuard
Wenn Sie Ihren Code verkleinern, müssen Sie verhindern, dass die Klassennamen Parcelable
, Serializable
und Enum
im Rahmen der Reduzierung verschleiert werden. Dazu haben Sie zwei Möglichkeiten:
- Verwenden Sie @Keep-Anmerkungen.
- Verwenden Sie Keepnames-Regeln.
In den folgenden Unterabschnitten werden diese Ansätze beschrieben.
@Keep-Anmerkungen verwenden
Im folgenden Beispiel werden @Keep
-Annotationen zu Modellklassendefinitionen 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 { ... }
Keepnames-Regeln verwenden
Sie können der Datei proguard-rules.pro
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 Ressourcen.