העברת נתונים בין יעדים

הניווט מאפשר לצרף נתונים לפעולת ניווט על ידי הגדרת ארגומנטים ליעד. לדוגמה, יעד של פרופיל משתמש עשוי לקבל מזהה משתמש ארגומנט כדי לקבוע איזה משתמש להציג.

באופן כללי, מומלץ מאוד להעביר רק את הכמות המינימלית של נתונים בין היעדים. לדוגמה, צריך להעביר מפתח כדי לאחזר אובייקט במקום להעביר את האובייקט עצמו, בתור השטח הכולל לכל המצבים השמורים מוגבלת ב-Android. אם אתם צריכים להעביר כמויות גדולות של נתונים, אפשר להשתמש ViewModel כמו שמתואר צפייה בסקירה הכללית של המודל.

הגדרת ארגומנטים של יעד

כדי להעביר נתונים בין יעדים, קודם צריך להגדיר את הארגומנט על ידי הוספתו היעד שמקבל אותו באמצעות השלבים הבאים:

  1. בעורך הניווט, לוחצים על היעד שמקבל את הארגומנט.
  2. בחלונית מאפיינים, לוחצים על הוספה (+).
  3. בחלון הוספת קישור לארגומנט שמופיע, מזינים את שם הארגומנט, סוג ארגומנט, האם הארגומנט הוא null וערך ברירת מחדל, אם הדרושים.
  4. לוחצים על הוספה. שימו לב שהארגומנט מופיע עכשיו בקטע ארגומנטים רשימה בחלונית מאפיינים.
  5. לאחר מכן, לוחצים על הפעולה המתאימה שמובילה ליעד הזה. עכשיו תוכלו לראות את הארגומנט החדש שהוספתם בחלונית מאפיינים. בקטע ערכי ברירת מחדל של ארגומנטים.
  6. אפשר גם לראות שהארגומנט נוסף ב-XML. לוחצים על הכרטיסייה טקסט. כדי לעבור לתצוגת XML ולראות שהארגומנט נוסף היעד שמקבל את הארגומנט. כך אפשר לראות דוגמה:

     <fragment android:id="@+id/myFragment" >
         <argument
             android:name="myArg"
             app:argType="integer"
             android:defaultValue="0" />
     </fragment>
    

סוגי הארגומנטים הנתמכים

ספריית הניווט תומכת בסוגי הארגומנטים הבאים:

סוג תחביר app:argType תמיכה בערכי ברירת מחדל טיפול במסלולים אפס
מספר שלם 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' כן לא
חבילה בהתאמה אישית app:argType="<type>", כאשר <type> הוא שם הסיווג המוגדר במלואו של Parcelable אפשר להשתמש בערך ברירת המחדל ' @null'. לא תומכת בערכי ברירת מחדל אחרים. לא כן
ניתן להתאמה אישית בסדרה app:argType="<type>", כאשר <type> הוא שם הסיווג המוגדר במלואו של Serializable אפשר להשתמש בערך ברירת המחדל ' @null'. לא תומכת בערכי ברירת מחדל אחרים. לא כן
טיפוסים בני מנייה (enum) מותאם אישית app:argType="<type>", כאשר <type> הוא השם המוגדר במלואו של טיפוס הטיפוסים (enum) כן - ערכי ברירת המחדל חייבים להתאים לשם הלא כשיר (למשל, "Success" כדי להתאים ל-MyEnum.You) לא לא

אם סוג ארגומנט תומך בערכי null, אפשר להצהיר על ערך ברירת מחדל של null באמצעות שימוש ב-android:defaultValue="@null".

אפשר לנתח ממחרוזות נתיבים, קישורי עומק ומזהי URI עם הארגומנטים שלהם. לא ניתן לעשות זאת באמצעות סוגי נתונים בהתאמה אישית כמו 'מגרשים' או ניתן להשתמש בהם בהמשכיות, כפי שמוצג בטבלה הקודמת. כדי להעביר נתונים מורכבים בהתאמה אישית, אחסנו את הנתונים במקום אחר, כגון ViewModel או מסד נתונים ולהעביר מזהה רק בזמן הניווט. ואז מאחזרים את הנתונים במיקום החדש אחרי שהניווט הסתיים.

כשבוחרים אחד מהסוגים המותאמים אישית, מופיעה תיבת הדו-שיח בחירת כיתה תוצג בקשה לבחור את הכיתה המתאימה לסוג הזה. הכרטיסייה Project מאפשרת לבחור כיתה מהפרויקט הנוכחי.

ניתן לבחור <infer type> להצגת ספריית הניווט לקבוע את הסוג על סמך הערך שצוין.

אפשר לסמן את Array כדי לציין שהארגומנט צריך להיות מערך של נבחר ערך סוג. שימו לב:

  • אין תמיכה במערכים של טיפוסים בני מנייה (enum) ומערכים של הפניות משאבים.
  • מערכי תמיכה תומכים בערכי null, ללא קשר לתמיכה במאפיין null מסוג הבסיס. לדוגמה, שימוש ב- האפליקציה 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 שנוצר מחלקות פשוטות של אובייקטים ו-builder בשביל ניווט בטוח לסוג גישה. ארגומנטים קשורים. מומלץ מאוד להשתמש ב-Safe Args לניווט ול העברת נתונים, כי זה מבטיח את בטיחות הסוג.

אם אתם לא משתמשים ב-Gradle, לא תוכלו להשתמש הפלאגין Args. במקרים כאלה, אפשר להשתמש בחבילות כדי ישירות להעביר נתונים.

כדי להוסיף 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, הקוד שנוצר מכיל את הדברים הבאים מקלידים את הסיווגים הבטוחים ואת השיטות הבטוחות לכל פעולה, כמו גם לכל שליחה היעד שמתקבל.

  • המערכת יוצרת כיתה לכל יעד שממנו בוצעה הפעולה. השם במחלקה הזו הוא השם של יעד המוצא שמצורף לסיומת "Directions". לדוגמה, אם יעד המוצא הוא מקטע בשם SpecifyAmountFragment, המחלקה שנוצרה נקראת SpecifyAmountFragmentDirections.

    לקטגוריה הזו יש שיטה לכל פעולה שהוגדרה בשדה היעד.

  • לכל פעולה שמשמשת להעברת הארגומנט, נוצרת מחלקה פנימית מבוסס על הפעולה. למשל, אם הפעולה נקראת confirmationAction, הכיתה נקראת ConfirmationAction. אם הפעולה מכילה ארגומנטים בלי defaultValue, אז צריך להשתמש בפונקציה מחלקה של הפעולה המשויכת כדי להגדיר את ערך הארגומנטים.

  • נוצרת כיתה ליעד המקבל. השם של הכיתה הזו הוא שם היעד שמצורף אליו במילה "Args". לדוגמה, אם השם של קטע היעד הוא ConfirmationFragment,. הכיתה נקראת ConfirmationFragmentArgs. שימוש בfromBundle() של הכיתה ולאחזור הארגומנטים.

הדוגמה הבאה מראה איך להשתמש בשיטות האלה כדי להגדיר ארגומנט להעביר אותו אל navigate() method:

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);
}

בקוד של היעד המקבל, משתמשים בשיטה getArguments() כדי לאחזר את החבילה ולהשתמש בתוכן שלה. כשמשתמשים ביחסי התלות של -ktx, משתמשי Kotlin יכולים גם להשתמש בבעל הגישה לנכס 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 עם פעולה גלובלית

כשמשתמשים בארגומנטים בטוחים עם פעולה גלובלית, צריך לספק ערך 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> יש שיטות שנוצרות לגישה לכל הפעולות הגלובליות המשויכות באמצעות כמתואר בקטע הקודם.

העברת נתונים בין יעדים באמצעות אובייקטים של חבילות

גם אם אתם לא משתמשים ב-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);

בקוד של היעד המקבל, משתמשים בשיטה 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 ליעד ההתחלה:

כדי לאחזר את הנתונים ביעד ההתחלה, צריך להתקשר Fragment.getArguments()

שיקולים ב-ProGuard

אם אתה מכווץ את הקוד, עליך למנוע את הParcelable, Serializable ו-Enum שמות של מחלקות מערפול קוד (obfuscated) כחלק תהליך ההקטנה. אפשר לעשות זאת באחת משתי הדרכים הבאות:

  • להשתמש בהערות @Keep.
  • להשתמש בכללי Keepname.

בקטעי המשנה הבאים מפורטות הגישות האלה.

שימוש בהערות @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 { ... }

שימוש בכללי Keepname

אפשר גם להוסיף כללים מסוג keepnames לקובץ proguard-rules.pro, כמו שמוצג בדוגמה הבאה:

proGuard-כללים.pro

...

-keepnames class com.path.to.your.ParcelableArg
-keepnames class com.path.to.your.SerializableArg
-keepnames class com.path.to.your.EnumArg

...

מקורות מידע נוספים

מידע נוסף על הניווט זמין במאמרים הבאים: משאבים נוספים.

דוגמיות

שיעורי Lab

סרטונים