Daten zwischen Zielen übergeben

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:

  1. Klicken Sie im Navigationseditor auf das Ziel, an das das Argument gesendet werden soll.
  2. Klicken Sie im Bereich Attribute auf Hinzufügen (+).
  3. Geben Sie im Fenster Argumentverknüpfung hinzufügen den Namen, den Argumenttyp, ob das Argument nullable ist, und bei Bedarf einen Standardwert ein.
  4. Klicken Sie auf Hinzufügen. Das Argument wird jetzt in der Liste Argumente im Bereich Attribute angezeigt.
  5. 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.
  6. 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 mit app: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 Klasse SpecifyAmountFragmentDirections.

    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 Namen ConfirmationAction. Wenn Ihre Aktion Argumente ohne defaultValue 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 Klasse ConfirmationFragmentArgs genannt. 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);
}

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:

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.

Codelabs

Videos