انتقال داده بین مقصد

ناوبری به شما امکان می دهد با تعریف آرگومان هایی برای یک مقصد، داده ها را به عملیات ناوبری متصل کنید. به عنوان مثال، یک مقصد نمایه کاربر ممکن است یک آرگومان شناسه کاربر برای تعیین اینکه کدام کاربر نمایش داده شود، استفاده کند.

به طور کلی، شما باید به شدت ترجیح دهید فقط حداقل مقدار داده را بین مقصد ارسال کنید. به عنوان مثال، شما باید یک کلید را برای بازیابی یک شی به جای عبور از خود شی ارسال کنید، زیرا فضای کل برای همه حالت های ذخیره شده در اندروید محدود است. اگر نیاز به انتقال مقادیر زیادی داده دارید، از ViewModel همانطور که در نمای کلی ViewModel توضیح داده شده است استفاده کنید.

آرگومان های مقصد را تعریف کنید

برای انتقال داده بین مقصدها، ابتدا آرگومان را با افزودن آن به مقصدی که آن را دریافت می کند با دنبال کردن مراحل زیر تعریف کنید:

  1. در ویرایشگر پیمایش ، روی مقصدی که آرگومان را دریافت می کند، کلیک کنید.
  2. در پانل ویژگی ها ، روی افزودن ( + ) کلیک کنید.
  3. در پنجره Add Argument Link که ظاهر می شود، نام آرگومان، نوع آرگومان، تهی بودن آرگومان و در صورت نیاز یک مقدار پیش فرض را وارد کنید.
  4. روی افزودن کلیک کنید. توجه داشته باشید که آرگومان اکنون در لیست Arguments در پانل Attributes ظاهر می شود.
  5. بعد، روی اقدام مربوطه که شما را به این مقصد می برد کلیک کنید. در پانل Attributes ، اکنون باید آرگومان جدید اضافه شده خود را در قسمت Argument Default Values ​​ببینید.
  6. همچنین می توانید ببینید که آرگومان در XML اضافه شده است. روی تب Text کلیک کنید تا به نمای XML بروید و توجه کنید که آرگومان شما به مقصدی که آرگومان را دریافت می‌کند اضافه شده است. یک مثال در زیر نشان داده شده است:

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

انواع آرگومان های پشتیبانی شده

کتابخانه Navigation از انواع آرگومان های زیر پشتیبانی می کند:

تایپ کنید دستور برنامه:argType پشتیبانی از مقادیر پیش فرض توسط مسیرها اداره می شود باطل شدنی
عدد صحیح app:argType = عدد صحیح بله بله خیر
شناور 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> نام کاملاً واجد شرایط enum است بله - مقادیر پیش‌فرض باید با نام نامشخص مطابقت داشته باشد (مثلاً "SUCCESS" برای مطابقت با MyEnum.SUCCESS). خیر خیر

اگر یک نوع آرگومان از مقادیر null پشتیبانی می کند، می توانید با استفاده از android:defaultValue="@null" یک مقدار پیش فرض null را اعلام کنید.

مسیرها، پیوندهای عمیق و URI ها با آرگومان هایشان می توانند از رشته ها تجزیه شوند. با استفاده از انواع داده های سفارشی مانند Parcelables و Serializables همانطور که در جدول قبل مشاهده می شود، این امکان وجود ندارد. برای انتقال داده‌های پیچیده سفارشی، داده‌ها را در جای دیگری مانند ViewModel یا پایگاه داده ذخیره کنید و فقط در حین پیمایش یک شناسه ارسال کنید. سپس پس از پایان ناوبری، داده ها را در مکان جدید بازیابی کنید.

هنگامی که یکی از انواع سفارشی را انتخاب می کنید، کادر گفتگوی Select Class ظاهر می شود و از شما می خواهد که کلاس مربوطه را برای آن نوع انتخاب کنید. تب Project به شما امکان می دهد یک کلاس از پروژه فعلی خود انتخاب کنید.

می توانید <نوع استنباط شده> را انتخاب کنید تا کتابخانه Navigation نوع را بر اساس مقدار ارائه شده تعیین کند.

می توانید Array را علامت بزنید تا نشان دهید که آرگومان باید آرایه ای از مقدار Type انتخاب شده باشد. به موارد زیر توجه کنید:

  • آرایه های enum و آرایه های منابع منابع پشتیبانی نمی شوند.
  • آرایه ها از مقادیر nullable پشتیبانی می کنند، صرف نظر از پشتیبانی از مقادیر nullable از نوع اصلی. به عنوان مثال، استفاده از 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 برای ارسال داده با نوع ایمنی استفاده کنید

مؤلفه Navigation دارای یک پلاگین Gradle به نام Safe Args است که کلاس های شی ساده و سازنده را برای ناوبری ایمن نوع و دسترسی به هر آرگومان مرتبط ایجاد می کند. Safe Args برای پیمایش و ارسال داده ها به شدت توصیه می شود، زیرا ایمنی نوع را تضمین می کند.

اگر از Gradle استفاده نمی کنید، نمی توانید از افزونه Safe Args استفاده کنید. در این موارد، می‌توانید از Bundles برای انتقال مستقیم داده‌ها استفاده کنید .

برای افزودن Safe Args به پروژه خود، classpath زیر را در فایل build.gradle سطح بالای خود قرار دهید:

شیار

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

کاتلین

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

همچنین باید یکی از دو افزونه موجود را اعمال کنید.

برای ایجاد کد زبان جاوا مناسب برای جاوا یا ماژول های ترکیبی جاوا و کاتلین، این خط را به فایل build.gradle برنامه یا ماژول خود اضافه کنید:

شیار

plugins {
  id 'androidx.navigation.safeargs'
}

کاتلین

plugins {
    id("androidx.navigation.safeargs")
}

از طرف دیگر، برای تولید کد Kotlin مناسب برای ماژول های فقط Kotlin اضافه کنید:

شیار

plugins {
  id 'androidx.navigation.safeargs.kotlin'
}

کاتلین

plugins {
    id("androidx.navigation.safeargs.kotlin")
}

شما باید android.useAndroidX=true را در فایل gradle.properties خود مطابق با مهاجرت به AndroidX داشته باشید.

پس از اینکه Safe Args را فعال کردید، کد تولید شده شما حاوی کلاس‌ها و روش‌های امن نوع زیر برای هر اقدام و همچنین با هر مقصد ارسال و دریافت است.

  • برای هر مقصدی که یک عمل از آنجا شروع می شود یک کلاس ایجاد می شود. نام این کلاس، نام مقصد مبدا است که با کلمه "Directions" ضمیمه شده است. به عنوان مثال، اگر مقصد مبدا قطعه ای باشد که SpecifyAmountFragment نام دارد، کلاس تولید شده SpecifyAmountFragmentDirections نامیده می شود.

    این کلاس برای هر اقدامی که در مقصد مبدا تعریف شده است، متدی دارد.

  • برای هر عملی که برای ارسال آرگومان استفاده می شود، یک کلاس داخلی ایجاد می شود که نام آن بر اساس عمل است. به عنوان مثال، اگر عملی به نام confirmationAction, کلاس ConfirmationAction نامیده می شود. اگر اکشن شما حاوی آرگومان‌هایی بدون defaultValue باشد، از کلاس اقدام مرتبط برای تنظیم مقدار آرگومان‌ها استفاده می‌کنید.

  • یک کلاس برای مقصد دریافت کننده ایجاد می شود. نام این کلاس، نام مقصدی است که با کلمه ارگ ​​ضمیمه شده است. به عنوان مثال، اگر قطعه مقصد ConfirmationFragment, کلاس تولید شده ConfirmationFragmentArgs نامیده می شود. از متد fromBundle() این کلاس برای بازیابی آرگومان ها استفاده کنید.

مثال زیر به شما نشان می دهد که چگونه از این متدها برای تنظیم آرگومان و ارسال آن به متد navigate() استفاده کنید:

کاتلین

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

جاوا

@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 می‌توانند از ویژگی delegate by navArgs() برای دسترسی به آرگومان‌ها استفاده کنند.

کاتلین

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

جاوا

@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>

Navigation یک کلاس Directions برای عنصر <navigation> تولید می کند که بر اساس مقدار android:id است. برای مثال، اگر یک عنصر <navigation> با android:id=@+id/main_nav دارید، کلاس تولید شده MainNavDirections نامیده می‌شود. همه مقاصد درون عنصر <navigation> روش هایی را برای دسترسی به تمام اقدامات جهانی مرتبط با استفاده از روش های مشابهی که در بخش قبل توضیح داده شد، ایجاد کرده اند.

انتقال داده بین مقصدها با اشیاء Bundle

اگر از Gradle استفاده نمی کنید، همچنان می توانید با استفاده از اشیاء Bundle ، آرگومان ها را بین مقصدها ارسال کنید. یک شی Bundle ایجاد کنید و آن را با استفاده از navigate() به مقصد ارسال کنید، مانند مثال زیر:

کاتلین

val bundle = bundleOf("amount" to amount)
view.findNavController().navigate(R.id.confirmationAction, bundle)

جاوا

Bundle bundle = new Bundle();
bundle.putString("amount", amount);
Navigation.findNavController(view).navigate(R.id.confirmationAction, bundle);

در کد مقصد دریافتی خود، از متد getArguments() برای بازیابی Bundle و استفاده از محتویات آن استفاده کنید:

کاتلین

val tv = view.findViewById<TextView>(R.id.textViewAmount)
tv.text = arguments?.getString("amount")

جاوا

TextView tv = view.findViewById(R.id.textViewAmount);
tv.setText(getArguments().getString("amount"));

داده ها را به مقصد شروع ارسال کنید

می توانید داده ها را به مقصد شروع برنامه خود ارسال کنید. ابتدا باید به صراحت یک Bundle بسازید که داده ها را در خود نگه دارد. در مرحله بعد، از یکی از روش های زیر برای ارسال Bundle به مقصد شروع استفاده کنید:

برای بازیابی داده ها در مقصد شروع، Fragment.getArguments() را فراخوانی کنید.

ملاحظات ProGuard

اگر کد خود را کوچک می‌کنید ، باید از مبهم شدن نام کلاس‌های Parcelable ، Serializable و Enum به عنوان بخشی از فرآیند کوچک‌سازی جلوگیری کنید. شما می توانید این کار را به یکی از دو روش انجام دهید:

  • از حاشیه نویسی @Keep استفاده کنید.
  • از قوانین keepnames استفاده کنید.

بخش های فرعی زیر این رویکردها را تشریح می کند.

از حاشیه نویسی @Keep استفاده کنید

مثال زیر حاشیه نویسی @Keep را به مدل تعاریف کلاس اضافه می کند:

کاتلین

@Keep class ParcelableArg : Parcelable { ... }

@Keep class SerializableArg : Serializable { ... }

@Keep enum class EnumArg { ... }

جاوا

@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

...

منابع اضافی

برای کسب اطلاعات بیشتر در مورد ناوبری، به منابع اضافی زیر مراجعه کنید.

نمونه ها

Codelabs

ویدیوها