בעזרת הניווט אפשר לצרף נתונים לפעולות ניווט על ידי הגדרת ארגומנטים ליעד. לדוגמה, יעד של פרופיל משתמש עשוי לקבל ארגומנטים של מזהי משתמשים כדי לקבוע איזה משתמש יוצג.
באופן כללי, מומלץ מאוד להעביר רק את כמות הנתונים המינימלית בין היעדים. לדוגמה, צריך להעביר מפתח כדי לאחזר אובייקט, במקום להעביר את האובייקט עצמו, כי נפח האחסון הכולל של כל המצבים השמורים מוגבל ב-Android. אם אתם צריכים להעביר כמויות גדולות של נתונים, השתמשו ב-ViewModel
כפי שמתואר בסקירה הכללית על ViewModel.
הגדרת ארגומנטים של יעד
כדי להעביר נתונים בין יעדים, קודם צריך להגדיר את הארגומנט על ידי הוספה שלו ליעד שמקבל אותו, לפי השלבים הבאים:
- בNavigation Editor, לוחצים על היעד שמקבל את הארגומנט.
- בחלונית מאפיינים, לוחצים על הוספה (+).
- בחלון Add Argument Link שמופיע, מזינים את שם הארגומנט, את סוג הארגומנט, את האפשרות אם הארגומנט יכול להיות null ואת ערך ברירת המחדל, אם יש צורך.
- לוחצים על הוספה. שימו לב שהארגומנט מופיע עכשיו ברשימה Arguments בחלונית Attributes.
- לאחר מכן, לוחצים על הפעולה המתאימה שתיקח אתכם ליעד הזה. בחלונית Attributes, הארגומנט החדש יתווסף לקטע Argument Default Values.
אפשר גם לראות שהארגומנט נוסף ב-XML. לוחצים על הכרטיסייה Text כדי לעבור לתצוגת XML, ומבחינים שהארגומנט נוסף ליעד שמקבל את הארגומנט. דוגמה מופיעה בהמשך:
<fragment android:id="@+id/myFragment" > <argument android:name="myArg" app:argType="integer" android:defaultValue="0" /> </fragment>
סוגי הארגומנטים הנתמכים
בספריית הניווט יש תמיכה בסוגי הארגומנטים הבאים:
סוג | תחביר של app:argType | תמיכה בערכי ברירת מחדל | טיפול על ידי נתיבים | Nullable |
---|---|---|---|---|
מספר שלם | app:argType="integer" | כן | כן | לא |
בלונים | app:argType="float" | כן | כן | לא |
ארוך | app:argType="long" | כן – ערכי ברירת המחדל תמיד צריכים להסתיים בסיומת 'L' (למשל '123L'). | כן | לא |
בוליאני | app:argType="boolean" | כן – 'true' או 'false' | כן | לא |
מחרוזת | app:argType="string" | כן | כן | כן |
הפניה למשאבים | app:argType="reference" | כן – ערכי ברירת המחדל חייבים להיות בפורמט "@resourceType/resourceName" (למשל, "@style/myCustomStyle") או "0" | כן | לא |
Parcelable בהתאמה אישית | app:argType="<type>", כאשר <type> הוא שם הכיתה המלא של Parcelable |
תמיכה בערך ברירת מחדל של @null. אין תמיכה בערכי ברירת מחדל אחרים. | לא | כן |
Serializable בהתאמה אישית | app:argType="<type>", כאשר <type> הוא שם הכיתה המלא של Serializable |
תמיכה בערך ברירת מחדל של @null. אין תמיכה בערכי ברירת מחדל אחרים. | לא | כן |
טיפוס בן מנייה (enum) בהתאמה אישית | app:argType="<type>", כאשר <type> הוא השם המלא של ה-enum | כן – ערכי ברירת המחדל חייבים להתאים לשם ללא הסיווג (למשל, 'SUCCESS' כדי להתאים ל-MyEnum.SUCCESS). | לא | לא |
אם סוג הארגומנט תומך בערכים null, אפשר להצהיר על ערך ברירת מחדל של null באמצעות android:defaultValue="@null"
.
אפשר לנתח מחרוזות כדי לקבל מסלולים, קישורי עומק ומזהי URI עם הארגומנטים שלהם. אי אפשר לעשות זאת באמצעות סוגי נתונים מותאמים אישית כמו Parcelables ו-Serializables, כפי שמוצג בטבלה הקודמת. כדי להעביר נתונים מורכבים בהתאמה אישית, שומרים את הנתונים במקום אחר, כמו ViewModel או מסד נתונים, ומעבירים רק מזהה במהלך הניווט. לאחר סיום הניווט, מאחזרים את הנתונים במיקום החדש.
כשבוחרים באחד מהסוגים בהתאמה אישית, מופיעה תיבת הדו-שיח Select Class (בחירת כיתה) עם בקשה לבחור את הכיתה המתאימה לסוג הזה. בכרטיסייה Project אפשר לבחור כיתה מהפרויקט הנוכחי.
אפשר לבחור באפשרות <inferred type> כדי לאפשר לספריית הניווט לקבוע את הסוג על סמך הערך שסופק.
אפשר לסמן את האפשרות Array כדי לציין שהארגומנט צריך להיות מערך של הערך שנבחר ב-Type. חשוב לזכור:
- אין תמיכה במערכים של ערכים מוגדרים מראש ובמערכים של הפניות למשאבים.
- מערכי נתונים תומכים בערכים nullable, ללא קשר לתמיכה בערכים nullable של הסוג הבסיסי. לדוגמה, השימוש ב-
app:argType="integer[]"
מאפשר להשתמש ב-app:nullable="true"
כדי לציין שאפשר להעביר מערך null. - במערכים יש תמיכה בערך ברירת מחדל יחיד, "@null". מערכי נתונים לא תומכים בשום ערך ברירת מחדל אחר.
שינוי של ארגומנט יעד בפעולה
כל הפעולות שמנווטות ליעד משתמשות בארגומנטים ברמת היעד ובערכים שמוגדרים כברירת מחדל. אם צריך, אפשר לשנות את ערך ברירת המחדל של ארגומנט (או להגדיר ערך אם הוא עדיין לא קיים) על ידי הגדרת ארגומנט ברמת הפעולה. הארגומנט הזה צריך להיות בעל אותו שם וסוג כמו הארגומנט שהוצהר ביעד.
הקוד הבא ב-XML מכריז על פעולה עם ארגומנט שמבטל את הארגומנט ברמת היעד מהדוגמה הקודמת:
<action android:id="@+id/startMyFragment"
app:destination="@+id/myFragment">
<argument
android:name="myArg"
app:argType="integer"
android:defaultValue="1" />
</action>
שימוש ב-Safe Args כדי להעביר נתונים עם אבטחת סוגים
לרכיב הניווט יש פלאגין של Gradle שנקרא Safe Args, שמייצר קלאסות פשוטות של אובייקטים ובונירים לניווט בטוח מבחינת סוגים ולגישה לכל הארגומנטים המשויכים. מומלץ מאוד להשתמש ב-Safe Args כדי לנווט ולהעביר נתונים, כי הוא מבטיח בטיחות סוגים.
אם אתם לא משתמשים ב-Gradle, לא תוכלו להשתמש בפלאגין SafeArgs. במקרים כאלה, אפשר להשתמש ב-Bundles כדי להעביר נתונים ישירות.
כדי להוסיף Safe Args לפרויקט, צריך לכלול את classpath
הבא בקובץ build.gradle
ברמה העליונה:
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") } }
בנוסף, צריך להחיל אחד משני הפלאגינים הזמינים.
כדי ליצור קוד בשפת Java שמתאים למודולים של Java או למודולים מעורבים של Java ו-Kotlin, מוסיפים את השורה הבאה לקובץ build.gradle
של האפליקציה או המודול:
Groovy
plugins { id 'androidx.navigation.safeargs' }
Kotlin
plugins { id("androidx.navigation.safeargs") }
לחלופין, כדי ליצור קוד Kotlin שמתאים למודולים של Kotlin בלבד, מוסיפים:
Groovy
plugins { id 'androidx.navigation.safeargs.kotlin' }
Kotlin
plugins { id("androidx.navigation.safeargs.kotlin") }
צריך להוסיף את android.useAndroidX=true
לקובץ gradle.properties
, בהתאם למאמר מעבר ל-AndroidX.
אחרי שמפעילים את Safe Args, הקוד שנוצר מכיל את הכיתות והשיטות הבאות לבטחון הסוג לכל פעולה, וגם לכל יעד שליחה ויעד קבלה.
המערכת יוצרת כיתה לכל יעד שממנו מגיעה פעולה. השם של הכיתה הזו הוא השם של היעד המקורי עם המילה 'הוראות'. לדוגמה, אם היעד המקור הוא קטע קוד בשם
SpecifyAmountFragment
, המחלקה שנוצרת נקראתSpecifyAmountFragmentDirections
.לכיתה הזו יש שיטה לכל פעולה שמוגדרת ביעד המקור.
לכל פעולה שמשמשת להעברת הארגומנט, נוצרת כיתה פנימית ששמה מבוסס על הפעולה. לדוגמה, אם הפעולה נקראת
confirmationAction,
, השם של המחלקה הואConfirmationAction
. אם הפעולה מכילה ארגומנטים ללאdefaultValue
, צריך להשתמש בכיתה המשויכת של הפעולה כדי להגדיר את הערך של הארגומנטים.נוצרת כיתה ליעד המקבל. שם המחלקה הזו הוא שם היעד עם המילה 'Args'. לדוגמה, אם קטע היעד נקרא
ConfirmationFragment,
, הכיתה שנוצרת תיקראConfirmationFragmentArgs
. משתמשים ב-methodfromBundle()
של הכיתה הזו כדי לאחזר את הארגומנטים.
בדוגמה הבאה מוסבר איך להשתמש בשיטות האלה כדי להגדיר ארגומנטים ולהעביר אותם לשיטה 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); }
בקוד של היעד המקבל, משתמשים ב-method getArguments()
כדי לאחזר את החבילה ולהשתמש בתוכן שלה. כשמשתמשים ביחסי התלות של -ktx
, משתמשי Kotlin יכולים להשתמש גם ב-delegate של המאפיין by navArgs()
כדי לגשת לארגומנטים.
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 עם פעולה גלובלית
כשמשתמשים ב-Safe Args עם פעולה גלובלית, צריך לספק ערך android:id
לאלמנט <navigation>
ברמה הבסיסית, כפי שמתואר בדוגמה הבאה:
<?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>
רכיב הניווט יוצר את הכיתה Directions
לרכיב <navigation>
על סמך הערך android:id
. לדוגמה, אם יש לכם רכיב <navigation>
עם android:id=@+id/main_nav
, המחלקה שנוצרת נקראת MainNavDirections
. לכל היעדים בתוך האלמנט <navigation>
נוצרו שיטות לגישה לכל הפעולות הגלובליות המשויכות, באמצעות אותן השיטות שמתוארות בקטע הקודם.
העברת נתונים בין יעדים באמצעות אובייקטים מסוג Bundle
אם אתם לא משתמשים ב-Gradle, עדיין תוכלו להעביר ארגומנטים בין יעדים באמצעות אובייקטים מסוג Bundle
. יוצרים אובייקט Bundle
ומעבירים אותו ליעד באמצעות navigate()
, כמו בדוגמה הבאה:
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);
בקוד של היעד המקבל, משתמשים ב-method getArguments()
כדי לאחזר את ה-Bundle
ולהשתמש בתוכן שלו:
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"));
העברת נתונים ליעד ההתחלה
אתם יכולים להעביר נתונים ליעד ההתחלה של האפליקציה. קודם צריך ליצור באופן מפורש Bundle
שמכיל את הנתונים. בשלב הבא, משתמשים באחת מהגישות הבאות כדי להעביר את Bundle
ליעד ההתחלה:
- אם אתם יוצרים את
NavHost
באופן פרוגרמטי, צריך לבצע קריאה ל-NavHostFragment.create(R.navigation.graph, args)
, כאשרargs
הוא ה-Bundle
שמכיל את הנתונים. - אחרת, אפשר להגדיר את הארגומנטים של יעד ההתחלה על-ידי קריאה לאחת מהעומסי יתר הבאים של
NavController.setGraph()
:- משתמשים במזהה התרשים:
navController.setGraph(R.navigation.graph, args)
- להשתמש בתרשים עצמו:
navController.setGraph(navGraph, args)
- משתמשים במזהה התרשים:
כדי לאחזר את הנתונים ביעד ההתחלה, צריך להפעיל את הפונקציה Fragment.getArguments()
.
שיקולים לגבי ProGuard
אם אתם מקצים קוד, עליכם למנוע ערפול של שמות המחלקות Parcelable
, Serializable
ו-Enum
כחלק מתהליך ההקטנה. יש שתי דרכים לעשות את זה:
- להשתמש בהערות ב-Keep.
- שימוש בכללי שמירה של שמות.
בקטעים הבאים מפורטות הגישות האלה.
שימוש בהערות ב-Keep
בדוגמה הבאה מתווספות הערות @Keep
להגדרות של סיווג המודלים:
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
אפשר גם להוסיף כללי keepnames
לקובץ proguard-rules.pro
, כפי שמוצג בדוגמה הבאה:
proguard-rules.pro
...
-keepnames class com.path.to.your.ParcelableArg
-keepnames class com.path.to.your.SerializableArg
-keepnames class com.path.to.your.EnumArg
...
מקורות מידע נוספים
מידע נוסף על ניווט זמין במקורות המידע הבאים.