تمرير البيانات بين الوجهات

يتيح لك التنقل إرفاق البيانات بعملية التنقل من خلال تحديد الوسيطات الخاصة بوجهة معيّنة على سبيل المثال، قد تأخذ وجهة الملف الشخصي للمستخدم رقم تعريف المستخدم. لتحديد المستخدم الذي سيتم عرضه.

بشكلٍ عام، يجب أن تفضّل بشدة تمرير أقل قدر من البيانات بين الوجهات. على سبيل المثال، يجب تمرير مفتاح لاسترداد كائن بدلاً من تمرير الكائن نفسه، كمساحة إجمالية لجميع الحالات المحفوظة متاحة فقط على Android. إذا كنت بحاجة إلى تمرير كميات كبيرة من البيانات، فاستخدم ViewModel كما هو موضّح في نظرة عامة على ViewModel.

تحديد وسيطات الوجهة

لتمرير البيانات بين الوجهات، حدد أولاً الوسيطة بإضافتها إلى الوجهة التي تستلمها باتّباع الخطوات التالية:

  1. في محرر التنقل، انقر على الوجهة التي تتلقّى الوسيطة.
  2. في لوحة السمات، انقر على إضافة (+).
  3. في نافذة إضافة رابط وسيطة التي تظهر، أدخِل اسم الوسيطة. ونوع الوسيطة، وما إذا كانت الوسيطة قابلة للقيم الفارغة، وقيمة تلقائية، إذا احتاجت.
  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" نعم - "صحيح" أو "خطأ" نعم لا
سلسلة 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> هو الاسم المؤهّل بالكامل للتعداد نعم - يجب أن تتطابق القيم التلقائية مع الاسم غير المؤهل (مثل "Success" لمطابقة MyEnum.Success). لا لا

إذا كان نوع الوسيطة يتوافق مع القيم الفارغة، يمكنك الإعلان عن قيمة تلقائية خالية باستخدام android:defaultValue="@null".

يمكن تحليل المسارات والروابط المؤدية إلى صفحات في التطبيق ومعرّفات الموارد المنتظمة (URI) مع وسيطاتها من السلاسل. لا يمكن ذلك باستخدام أنواع بيانات مخصّصة مثل قطع الأراضي قابلة للتسلسل كما هو موضح في الجدول السابق. لتمرير البيانات المعقدة والمخصصة، قم بتخزين البيانات في مكان آخر مثل 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>

استخدام "الوسيطات الآمنة" لتمرير البيانات مع الحفاظ على أمان النوع

يشتمل مكوِّن التنقل على مكون إضافي لنظام Gradle يسمى "الوسيطات الآمنة" التي تنشئ فئات الكائنات البسيطة ومنصات الإنشاء للتنقل الآمن من ناحية النوع والوصول إلى أي الوسيطات المرتبطة. يوصى بشدة باستخدام الوسيطات الآمنة للتنقل وتمرير البيانات، لأنها تضمن أمان الكتابة.

إذا كنت لا تستخدم Gradle، فلا يمكنك استخدام المكوّن الإضافي Args. وفي هذه الحالات، يمكنك استخدام الحِزم لإجراء وتمرير البيانات.

لإضافة الوسيطات الآمنة إلى مشروعك، عليك تضمين classpath التالي في ملف build.gradle ذي المستوى الأعلى:

Groovy

buildscript {
    repositories {
        google()
    }
    dependencies {
        def nav_version = "2.8.0"
        classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
    }
}

Kotlin

buildscript {
    repositories {
        google()
    }
    dependencies {
        val nav_version = "2.8.0"
        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

بعد تفعيل الوسيطات الآمنة، يحتوي الرمز الذي أنشأته على ما يلي: اكتب فئات وطرقًا آمنة لكل إجراء وكذلك مع كل عملية إرسال وجهة الاستلام.

  • يتمّ إنشاء فئة لكلّ وجهة ينشأ فيها الإجراء. الاسم في هذه الفئة هو اسم الوجهة الأصلية ملحقة بـ كلمة "الاتجاهات". على سبيل المثال، إذا كانت الوجهة الأصلية جزءًا التي تحمل اسم 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 إلى وجهة البداية:

لاسترداد البيانات في وجهة البدء، اتصل 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

...

مصادر إضافية

للاطّلاع على مزيد من المعلومات حول التنقّل، يُرجى الرجوع إلى ما يلي: والموارد الإضافية.

نماذج

الدروس التطبيقية حول الترميز

الفيديوهات