يتيح لك التنقل إرفاق بيانات بعملية تنقُّل من خلال تحديد الوسيطات للوجهة. على سبيل المثال، قد تأخذ وجهة الملف الشخصي للمستخدم وسيطة رقم تعريف المستخدم لتحديد المستخدم الذي سيتم عرضه.
بوجه عام، يجب أن تفضل بشدة تمرير الحد الأدنى فقط من البيانات
بين الوجهات. على سبيل المثال، يجب تمرير مفتاح لاسترداد كائن بدلاً من تمرير الكائن نفسه، لأن المساحة الإجمالية لجميع الحالات المحفوظة
تكون محدودة في Android. إذا كنت بحاجة إلى تمرير كميات كبيرة من البيانات، استخدِم ViewModel
كما هو موضّح في نظرة عامة على ViewModel.
تحديد وسيطات الوجهة
لتمرير البيانات بين الوجهات، حدِّد أولاً الوسيطة بإضافتها إلى الوجهة التي تستلمها، وذلك باتّباع الخطوات التالية:
- في محرر التنقل، انقر على الوجهة التي تتلقّى الوسيطة.
- في لوحة السمات، انقر على إضافة (+).
- في النافذة إضافة رابط وسيطة التي تظهر، أدخِل اسم الوسيطة ونوع الوسيطة وما إذا كانت الوسيطة قابلة للتعديل وقيمة تلقائية، إذا لزم الأمر.
- انقر على إضافة. لاحظ أن الوسيطة تظهر الآن في قائمة الوسيطات في لوحة السمات.
- بعد ذلك، انقر على الإجراء المقابل الذي ينقلك إلى هذه الوجهة. في لوحة السمات، من المفترض أن تظهر لك الآن الوسيطة المضافة حديثًا في القسم القيم التلقائية للوسيطة.
يمكنك أيضًا أن ترى أنه تمت إضافة الوسيطة في XML. انقر على علامة التبويب نص للتبديل إلى عرض XML، ولاحظ أنه تمت إضافة الوسيطة إلى الوجهة التي تتلقى الوسيطة. يظهر مثال فيما يلي:
<fragment android:id="@+id/myFragment" > <argument android:name="myArg" app:argType="integer" android:defaultValue="0" /> </fragment>
أنواع الوسائط المتوافقة
تتوافق مكتبة التنقّل مع أنواع الوسيطات التالية:
Type | بنية app:argType | دعم القيم التلقائية | تمت معالجتها حسب المسارات | قيمة فارغة |
---|---|---|---|---|
عدد صحيح | app:argType="integer" | نعم | نعم | لا |
نافذة عائمة | app:argType="float" | نعم | نعم | لا |
طويلة | app:argType="long" | نعم، يجب أن تنتهي القيم التلقائية دائمًا باللاحقة "L" (مثل "123L"). | نعم | لا |
قيمة منطقية | app:argType="boolean" | نعم - "صحيح" أو "خطأ" | نعم | لا |
سلسلة | app:argType="string" | نعم | نعم | نعم |
مرجع الموارد | app:argType="reference" | نعم - يجب أن تكون القيم التلقائية على هيئة "@resourceType/resourceName" (على سبيل المثال "@style/myCustomStyle") أو "0" | نعم | لا |
حزمة مخصّصة | app:argType="<type>"، حيث يكون <type> هو اسم الفئة المؤهَّل بالكامل لـ Parcelable |
يتوافق مع قيمة تلقائية لـ "@null". لا يتوافق مع القيم التلقائية الأخرى. | لا | نعم |
قابل للتسلسل المخصّص | app:argType="<type>"، حيث يكون <type> هو اسم الفئة المؤهَّل بالكامل لـ Serializable |
يتوافق مع قيمة تلقائية لـ "@null". لا يتوافق مع القيم التلقائية الأخرى. | لا | نعم |
قيم تعداد مخصّص | app:argType="<type>"، حيث يكون <type> هو الاسم المؤهّل بالكامل للتعداد | نعم - يجب أن تتطابق القيم التلقائية مع الاسم غير المؤهَّل (على سبيل المثال، "نجاح" لمطابقة MyEnum.SUCCESS). | لا | لا |
إذا كان نوع الوسيطة يتيح استخدام القيم الفارغة، يمكنك تعريف القيمة التلقائية بالقيمة "فارغ" باستخدام السمة android:defaultValue="@null"
.
يمكن تحليل المسارات وروابط الصفحات في التطبيق وعناوين URI مع وسيطاتها من السلاسل. لا يمكن إجراء ذلك باستخدام أنواع البيانات المخصّصة مثل Parcelables وSerialables كما هو موضّح في الجدول السابق. لتمرير البيانات المعقدة المخصصة، خزن البيانات في مكان آخر مثل ViewModel أو قاعدة البيانات، ومرر مُعرّفًا فقط أثناء التنقل؛ ثم استرجع البيانات في الموقع الجديد بعد انتهاء التنقل.
عند اختيار أحد الأنواع المخصّصة، يظهر مربع الحوار اختيار صف ويطلب منك اختيار الفئة المناسبة لهذا النوع. تتيح لك علامة تبويب المشروع اختيار فئة من مشروعك الحالي.
يمكنك اختيار <intered type> لجعل مكتبة التنقل تحدد النوع استنادًا إلى القيمة المقدمة.
يمكنك التحقق من صفيف للإشارة إلى أن الوسيطة يجب أن تكون مصفوفة من قيمة النوع المحددة. ملاحظات:
- لا يتوفر مصفوفات التعداد ومصفوفات مراجع الموارد.
- تدعم المصفوفات القيم القابلة للقيم الفارغة، بصرف النظر عن دعم القيم القابلة للقيم الفارغة من النوع الأساسي. على سبيل المثال، يتيح لك استخدام
app:argType="integer[]"
استخدامapp:nullable="true"
للإشارة إلى أنّ تمرير مصفوفة فارغة أمر مقبول. - تتيح الصفائف قيمة تلقائية واحدة، وهي "@null". الصفائف لا تدعم أي قيمة افتراضية أخرى.
إلغاء وسيطة وجهة في إجراء معيّن
يتم استخدام الوسيطات على مستوى الوجهة والقيم الافتراضية من خلال جميع الإجراءات التي تنتقل إلى الوجهة. إذا لزم الأمر، يمكنك إلغاء القيمة التلقائية للوسيطة (أو تعيين قيمة إذا لم تكن موجودة بالفعل) من خلال تحديد وسيطة على مستوى الإجراء. يجب أن تحمل هذه الوسيطة اسم ونوع نفس الوسيطة التي تم تعريفها في الوجهة.
يعلن ملف XML التالي عن إجراء يتضمن وسيطة تتجاوز الوسيطة على مستوى الوجهة من المثال السابق:
<action android:id="@+id/startMyFragment"
app:destination="@+id/myFragment">
<argument
android:name="myArg"
app:argType="integer"
android:defaultValue="1" />
</action>
استخدام الوسيطات الآمنة لتمرير البيانات بنوع أمان
يحتوي مكوِّن التنقل على مكوّن Gradle الإضافي يُسمى Safe Args، والذي يُنشئ فئات كائنات ومنشئات بسيطة للتنقل الآمن من النوع والوصول إلى أي وسيطات مرتبطة. يوصى بشدة باستخدام الوسيطات الآمنة للتنقل وتمرير البيانات، لأنها تضمن أمان النوع.
إذا كنت لا تستخدم Gradle، لا يمكنك استخدام المكوّن الإضافي Safe Args. وفي هذه الحالات، يمكنك استخدام الحِزم لتمرير البيانات مباشرةً.
لإضافة الوسيطات الآمنة
إلى مشروعك، عليك تضمين classpath
التالي في ملف build.gradle
ذي المستوى الأعلى:
Groovy
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") } }
ويجب أيضًا تطبيق أحد المكوّنات الإضافية المتاحة.
لإنشاء رمز لغة 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()
:
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 + ""); }
استخدام الوسيطات الآمنة مع إجراء عام
عند استخدام الوسيطات الآمنة مع إجراء عام، يجب توفير قيمة 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
إلى وجهة البداية:
- إذا كنت تنشئ
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 التوضيحية.
- استخدام قواعد Keepnames
توضّح الأقسام الفرعية التالية هذه الأساليب.
استخدام تعليقات 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
...
مراجع إضافية
لمعرفة المزيد حول التنقل، راجع الموارد الإضافية التالية.