Daten zwischen Zielen übergeben

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:

  1. Klicken Sie im Navigationseditor auf das Ziel, das das Argument empfängt.
  2. Klicken Sie im Bereich Attribute auf Hinzufügen (+).
  3. 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.
  4. Klicken Sie auf Hinzufügen. Das Argument wird jetzt im Bereich Attribute in der Liste Argumente angezeigt.
  5. 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.
  6. 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 beispielsweise app: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.

Fügen Sie die folgende classpath in die build.gradle-Datei der obersten Ebene ein, um Ihrem Projekt Safe Args hinzuzufügen:

Groovig

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 von zwei verfügbaren Plug-ins anwenden.

Wenn Sie Java-Sprachcode generieren möchten, der für Java oder gemischte Java- und Kotlin-Module geeignet ist, fügen Sie diese Zeile in die Datei build.gradle Ihrer App oder Ihres Moduls ein:

Groovig

plugins {
  id 'androidx.navigation.safeargs'
}

Kotlin

plugins {
    id("androidx.navigation.safeargs")
}

Zum Generieren von Kotlin-Code, der nur für Kotlin-basierte Module geeignet ist, können Sie alternativ Folgendes hinzufügen:

Groovig

plugins {
  id 'androidx.navigation.safeargs.kotlin'
}

Kotlin

plugins {
    id("androidx.navigation.safeargs.kotlin")
}

Wie unter Zu AndroidX migrieren beschrieben, muss android.useAndroidX=true in Ihrer gradle.properties-Datei enthalten sein.

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 Klasse SpecifyAmountFragmentDirections.

    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 Namen ConfirmationAction. Wenn Ihre Aktion Argumente ohne defaultValue 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 Klasse ConfirmationFragmentArgs. Verwenden Sie die Methode fromBundle() 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:

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.

Produktproben

Codelabs

Videos