Funkcja nawigacji umożliwia dołączanie danych do operacji nawigacji przez zdefiniowanie argumentów dla miejsca docelowego. Na przykład miejsce docelowe profilu użytkownika może używać argumentu identyfikatora użytkownika, aby określić, którego użytkownika wyświetlić.
Ogólnie zalecamy przekazywanie między miejscami docelowymi tylko minimalnej ilości danych. Na przykład, aby pobrać obiekt, należy przekazać klucz, a nie sam obiekt, ponieważ łączna ilość miejsca na wszystkie zapisane stany jest ograniczona na Androidzie. Jeśli chcesz przekazać duże ilości danych, użyj ViewModel
zgodnie z opisem w omówieniu ViewModel.
Definiowanie argumentów miejsca docelowego
Aby przekazywać dane między punktami docelowymi, najpierw zdefiniuj argument, dodając go do punktu docelowego, który go odbiera. Aby to zrobić:
- W Edytorze nawigacji kliknij miejsce docelowe, które ma otrzymywać argument.
- W panelu Atrybuty kliknij Dodaj (+).
- W wyświetlonym oknie Dodaj link argumentu wpisz nazwę argumentu, jego typ, informację, czy argument może być pusty, oraz wartość domyślną (jeśli jest potrzebna).
- Kliknij Dodaj. Zwróć uwagę, że argument jest teraz widoczny na liście Argumenty w panelu Atrybuty.
- Następnie kliknij odpowiednie działanie, które przeniesie Cię do tego miejsca docelowego. W panelu Atrybuty nowo dodany argument powinien się teraz wyświetlać w sekcji Domyślne wartości argumentu.
Możesz też sprawdzić, że argument został dodany w pliku XML. Kliknij kartę Tekst, aby przełączyć się na widok XML. Zobaczysz, że argument został dodany do miejsca docelowego, które go przyjmuje. Przykład:
<fragment android:id="@+id/myFragment" > <argument android:name="myArg" app:argType="integer" android:defaultValue="0" /> </fragment>
Obsługiwane typy argumentów
Biblioteka Nawigacja obsługuje te typy argumentów:
Typ | Składnia app:argType | Obsługa wartości domyślnych | Obsługiwane przez trasy | Dopuszczalna wartość null |
---|---|---|---|---|
Liczba całkowita | app:argType="integer" | Tak | Tak | Nie |
Pływające | app:argType="float" | Tak | Tak | Nie |
Długie | app:argType="long" | Tak – wartości domyślne muszą zawsze kończyć się sufiksem „L” (np. „123L”). | Tak | Nie |
Wartość logiczna | app:argType="boolean" | Tak – „true” lub „false” | Tak | Nie |
Ciąg znaków | app:argType="string" | Tak | Tak | Tak |
Odniesienie do zasobu | app:argType="reference" | Tak – wartości domyślne muszą mieć format „@resourceType/resourceName” (np. „@style/myCustomStyle”) lub „0”. | Tak | Nie |
Niestandardowe obiekty Parcelable | app:argType="<type>", gdzie <type> to pełna i jednoznaczna nazwa klasy Parcelable |
Obsługuje wartość domyślną „@null”. Nie obsługuje innych wartości domyślnych. | Nie | Tak |
Niestandardowa serializacja | app:argType="<type>", gdzie <type> to pełna i jednoznaczna nazwa klasy Serializable |
Obsługuje wartość domyślną „@null”. Nie obsługuje innych wartości domyślnych. | Nie | Tak |
Niestandardowe wyliczenie | app:argType="<type>", gdzie <type> to pełna i jednoznaczna nazwa wyliczenia. | Tak – wartości domyślne muszą być zgodne z nazwą bezkwalifikowaną (np. „SUCCESS” musi być zgodne z MyEnum.SUCCESS). | Nie | Nie |
Jeśli typ argumentu obsługuje wartości null, możesz zadeklarować wartość domyślną null, używając android:defaultValue="@null"
.
Trasy, precyzyjne linki i identyfikatory URI wraz z ich argumentami mogą być analizowane na podstawie ciągów znaków. Nie jest to możliwe w przypadku niestandardowych typów danych, takich jak Parcelables i Serializables, jak widać w poprzedniej tabeli. Aby przekazywać niestandardowe dane złożone, przechowuj je w innym miejscu, np. w ViewModel lub bazie danych, i podczas nawigacji przekazuj tylko identyfikator. Następnie po zakończeniu nawigacji pobierz dane z nowej lokalizacji.
Po wybraniu jednego z typów niestandardowych pojawi się okno Wybierz zajęcia, w którym możesz wybrać zajęcia odpowiadające temu typowi. Na karcie Projekt możesz wybrać klasę z bieżącego projektu.
Możesz wybrać <inferred type>, aby biblioteka Nawigacja określiła typ na podstawie podanej wartości.
Możesz zaznaczyć pole Tablica, aby wskazać, że argument powinien być tablicą o wybranej wartości Typ. Uwaga:
- Tablice typów wyliczeniowych i tablice odwołań do zasobów nie są obsługiwane.
- Tablice obsługują wartości opcjonalne niezależnie od obsługi wartości opcjonalnych typu podstawowego. Na przykład użycie funkcji
app:argType="integer[]"
pozwala użyć funkcjiapp:nullable="true"
, aby wskazać, że przekazanie tablicy null jest dopuszczalne. - Tablice obsługują jedną wartość domyślną, „@null”. Tablice nie obsługują żadnych innych wartości domyślnych.
Zastępowanie argumentu miejsca docelowego w działaniu
Argumenty i wartości domyślne na poziomie miejsca docelowego są używane przez wszystkie działania, które przekierowują do tego miejsca. W razie potrzeby możesz zastąpić domyślną wartość argumentu (lub ustawić ją, jeśli jeszcze nie istnieje), definiując argument na poziomie działania. Ten argument musi mieć taką samą nazwę i taki sam typ jak argument zadeklarowany w miejscu docelowym.
Ten kod XML deklaruje działanie z argumentem, który zastępuje argument dotyczący poziomu miejsca docelowego z poprzedniego przykładu:
<action android:id="@+id/startMyFragment"
app:destination="@+id/myFragment">
<argument
android:name="myArg"
app:argType="integer"
android:defaultValue="1" />
</action>
Przekazywanie danych z zabezpieczeniami typu za pomocą Safe Args
Komponent Nawigacja ma wtyczkę Gradle o nazwie Safe Args, która generuje proste klasy obiektów i klasy konstruktora na potrzeby bezpiecznej nawigacji typu oraz dostępu do wszystkich powiązanych argumentów. Zalecamy używanie Safe Args do nawigacji i przekazywania danych, ponieważ zapewnia to bezpieczeństwo typów.
Jeśli nie używasz Gradle, nie możesz korzystać z wtyczki Safe Args. W takich przypadkach możesz korzystać z pakietów, aby przekazywać dane bezpośrednio.
Aby dodać Safe Args do projektu, umieść w pliku najwyższego poziomu build.gradle
ten element classpath
:
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") } }
Musisz też zastosować jedną z 2 dostępnych wtyczek.
Aby wygenerować kod w języku Java odpowiedni dla modułów Java lub mieszanych modułów Java i Kotlin, dodaj ten wiersz do pliku build.gradle
aplikacji lub modułu:
Groovy
plugins { id 'androidx.navigation.safeargs' }
Kotlin
plugins { id("androidx.navigation.safeargs") }
Aby wygenerować kod Kotlina odpowiedni dla modułów tylko w Kotlinie, dodaj:
Groovy
plugins { id 'androidx.navigation.safeargs.kotlin' }
Kotlin
plugins { id("androidx.navigation.safeargs.kotlin") }
W pliku gradle.properties
musisz mieć wartość android.useAndroidX=true
, zgodnie z informacjami w artykule Przenoszenie na AndroidX.
Po włączeniu opcji Bezpieczne argumenty wygenerowany kod zawiera te bezpieczne klasy i metody dla każdego działania oraz dla każdego miejsca docelowego wysyłania i odbierania.
Klasa jest tworzona dla każdego miejsca docelowego, w którym występuje działanie. Nazwa tej klasy to nazwa miejsca docelowego z dołączonym słowem „Wskazówki”. Jeśli na przykład miejsce docelowe pochodzenia to fragment o nazwie
SpecifyAmountFragment
, wygenerowana klasa będzie się nazywaćSpecifyAmountFragmentDirections
.Ta klasa ma metodę dla każdego działania zdefiniowanego w pochodzącym miejscu docelowym.
Dla każdego działania używanego do przekazywania argumentu tworzona jest klasa wewnętrzna, której nazwa jest określana na podstawie działania. Jeśli na przykład działanie ma nazwę
confirmationAction,
, klasa ma nazwęConfirmationAction
. Jeśli Twoje działanie zawiera argumenty bez parametrudefaultValue
, możesz użyć powiązanej klasy działania, aby ustawić wartość argumentów.Dla docelowego miejsca docelowego zostaje utworzona klasa. Nazwa tej klasy to nazwa miejsca docelowego z dołączonym słowem „Args”. Jeśli na przykład fragment docelowy ma nazwę
ConfirmationFragment,
, wygenerowana klasa będzie się nazywaćConfirmationFragmentArgs
. Aby pobrać argumenty, użyj metodyfromBundle()
tej klasy.
Z tego przykładu dowiesz się, jak użyć tych metod do ustawienia argumentu i przekazania go do metody 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); }
W kodzie miejsca docelowego odbioru użyj metody getArguments()
, aby pobrać pakiet i użyć jego zawartości. Użytkownicy Kotlina mogą też używać delegata właściwości by navArgs()
do uzyskiwania dostępu do argumentów podczas korzystania z zależności -ktx
.
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 + ""); }
Używanie bezpiecznych argumentów w przypadku działania globalnego
Jeśli używasz argumentów bezpiecznych w działaniu globalnym, musisz podać wartość android:id
dla elementu <navigation>
wyższego poziomu, jak w tym przykładzie:
<?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>
Nawigacja generuje klasę Directions
dla elementu <navigation>
na podstawie wartości android:id
. Jeśli na przykład masz element <navigation>
z wartością android:id=@+id/main_nav
, wygenerowana klasa będzie się nazywać MainNavDirections
. Wszystkie miejsca docelowe w elemencie <navigation>
mają wygenerowane metody dostępu do wszystkich powiązanych działań globalnych za pomocą tych samych metod, co opisano w poprzedniej sekcji.
Przesyłanie danych między miejscami docelowymi za pomocą obiektów pakietu
Jeśli nie używasz Gradle, możesz nadal przekazywać argumenty między miejscami docelowymi, używając obiektów Bundle
. Utwórz obiekt Bundle
i przekaż go do miejsca docelowego za pomocą elementu navigate()
, jak w tym przykładzie:
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);
W kodzie miejsca docelowego odbioru użyj metody getArguments()
, aby pobrać plik Bundle
i używać jego zawartości:
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"));
Przekazywanie danych do miejsca docelowego
Możesz przekazywać dane do miejsca docelowego startowego aplikacji. Najpierw musisz jawnie utworzyć obiekt Bundle
, który będzie przechowywać dane. Następnie użyj jednej z tych metod, aby przekazać Bundle
do miejsca docelowego:
- Jeśli
NavHost
tworzysz programowo, wywołaj funkcjęNavHostFragment.create(R.navigation.graph, args)
, gdzieargs
toBundle
zawierający Twoje dane. - W przeciwnym razie możesz ustawić argumenty początkowego miejsca docelowego, wywołując jedną z tych przeciążeń funkcji
NavController.setGraph()
:- Użyj identyfikatora grafu:
navController.setGraph(R.navigation.graph, args)
- Użyj samego wykresu:
navController.setGraph(navGraph, args)
- Użyj identyfikatora grafu:
Aby pobrać dane z miejsca docelowego, zadzwoń pod numer Fragment.getArguments()
.
Uwagi dotyczące ProGuard
Jeśli zmniejszasz rozmiar kodu, musisz zadbać o to, aby nazwy klas Parcelable
, Serializable
i Enum
nie zostały zaciemnione w ramach procesu minifikacji. Możesz to zrobić na 2 sposoby:
- Używanie adnotacji @Keep.
- Używaj reguł dotyczących zachowywania nazw.
W następnych podrozdziałach omawiamy te podejścia.
Używanie adnotacji @Keep
W tym przykładzie adnotacje @Keep
dodajemy do definicji klasy modelu:
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 { ... }
Używanie reguł dotyczących zachowywania nazw
Do pliku proguard-rules.pro
możesz też dodać reguły keepnames
, jak pokazano w tym przykładzie:
proguard-rules.pro
...
-keepnames class com.path.to.your.ParcelableArg
-keepnames class com.path.to.your.SerializableArg
-keepnames class com.path.to.your.EnumArg
...
Dodatkowe materiały
Więcej informacji o nawigacji znajdziesz w tych dodatkowych materiałach.