يتيح لك التنقّل إرفاق البيانات بعملية تنقّل من خلال تحديد واسِمات لوجهة معيّنة. على سبيل المثال، قد تأخذ وجهة الملف الشخصي للمستخدم وسيطة رقم تعريف مستخدم لتحديد المستخدم الذي سيتم عرضه.
بشكل عام، يجب تفضيل نقل الحد الأدنى من البيانات
فقط بين الوجهات. على سبيل المثال، يجب تمرير مفتاح لاسترداد عنصر
بدلاً من تمرير العنصر نفسه، لأنّ المساحة الإجمالية لجميع الحالات المحفوظة
محدودة على Android. إذا كنت بحاجة إلى تمرير كميات كبيرة من البيانات، استخدِم
ViewModel
كما هو موضّح في
نظرة عامة على ViewModel.
تحديد وسيطات الوجهة
لنقل البيانات بين الوجهات، حدِّد أولاً الوسيطة من خلال إضافتها إلى الوجهة التي تتلقّاها باتّباع الخطوات التالية:
- في محرر التنقّل، انقر على الوجهة التي تتلقّى الوسيطة.
- في لوحة السمات، انقر على إضافة (+).
- في نافذة إضافة رابط وسيطة التي تظهر، أدخِل اسم الوسيطة ونوع الوسيطة وما إذا كانت الوسيطة قابلة للتغيير وقيمة تلقائية، إذا لزم الأمر.
- انقر على إضافة. يُرجى ملاحظة أنّ الوسيطة تظهر الآن في قائمة الوسيطات في لوحة السمات.
- بعد ذلك، انقر على الإجراء المقابل الذي ينقلك إلى هذه الوجهة. في لوحة السمات، من المفترض أن تظهر لك الآن الوسيطة المُضافة حديثًا في قسم القيم التلقائية للوسيطة.
يمكنك أيضًا الاطّلاع على أنّه تمت إضافة الوسيطة في ملف 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" | نعم - "صحيح" أو "خطأ" | نعم | لا |
سلسلة | 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". لا تتيح القيم التلقائية الأخرى. | لا | نعم |
التعداد المخصّص | app:argType="<type>"، حيث يكون <type> هو الاسم المؤهَّل بالكامل للقائمة المحدودة | نعم، يجب أن تتطابق القيم التلقائية مع الاسم غير المحدَّد (مثل "SUCCESS" لمطابقة MyEnum.SUCCESS). | لا | لا |
إذا كان نوع الوسيطة يتيح القيم الخالية، يمكنك تحديد قيمة تلقائية هي
null باستخدام android:defaultValue="@null"
.
يمكن تحليل المسارات والروابط لصفحات في التطبيق وعناوين URL مع الوسيطات من السلاسل. لا يمكن إجراء ذلك باستخدام أنواع البيانات المخصّصة، مثل Parcelables و Serializables كما هو موضّح في الجدول السابق. لنقل البيانات المخصّصة المعقدة، يمكنك تخزين البيانات في مكان آخر، مثل ViewModel أو قاعدة بيانات، ويجب فقط تمرير معرّف أثناء التنقّل، ثم استرداد البيانات في الموقع الجديد بعد انتهاء التنقّل.
عند اختيار أحد الأنواع المخصّصة، يظهر مربّع الحوار اختيار الصف ويُطلب منك اختيار الصف المقابل لهذا النوع. تتيح لك علامة التبويب المشروع اختيار صف من مشروعك الحالي.
يمكنك اختيار <inferred 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>
استخدام Safe Args لتمرير البيانات مع أمان النوع
يحتوي مكوّن التنقّل على مكوّن إضافي لنظام Gradle يُسمى Safe Args يُنشئ فئات بسيطة للكائنات وأدوات الإنشاء للتنقّل الآمن حسب النوع والوصول إلى أي مَعلمات مرتبطة. ننصح بشدة باستخدام Safe Args للتنقّل في البيانات ونقلها، لأنّه يضمن أمان النوع.
إذا كنت لا تستخدم Gradle، لا يمكنك استخدام المكوّن الإضافي Safe Args. في هذه الحالات، يمكنك استخدام الحِزم ل تمرير البيانات مباشرةً.
لإضافة Safe Args
إلى مشروعك، أدرِج classpath
التالي في ملف build.gradle
من المستوى الأعلى:
رائع
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
في تطبيقك أو وحدتك:
رائع
plugins { id 'androidx.navigation.safeargs' }
Kotlin
plugins { id("androidx.navigation.safeargs") }
بدلاً من ذلك، لإنشاء رمز Kotlin مناسب للوحدات التي تستخدم Kotlin فقط، أضِف ما يلي:
رائع
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
. استخدِم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 + ""); }
استخدام 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>
باستخدام الطرق نفسها الموضّحة في القسم السابق.
تمرير البيانات بين الوجهات باستخدام عناصر الحِزم
إذا لم تكن تستخدم 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()
ل retrieving the 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
...
مصادر إضافية
لمزيد من المعلومات عن التنقّل، يمكنك الرجوع إلى المراجع التالية الإضافية.