حفظ حالة التنقّل وإدارتها

توضّح الأقسام التالية استراتيجيات لحفظ سجلّ الرجوع وتخزين الحالة المرتبطة بالإدخالات في سجلّ الرجوع.

حفظ سجلّ الرجوع

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

استخدام rememberNavBackStack

تم تصميم الدالة القابلة للإنشاء rememberNavBackStack لإنشاء سجلّ رجوع يستمر في العمل عند حدوث تغييرات في الإعدادات أو إيقاف العملية.

لكي يعمل rememberNavBackStack بشكل صحيح، يجب أن يستوفي كل مفتاح في سجلّ الرجوع المتطلبات التالية:

  • تنفيذ واجهة NavKey: يجب أن ينفّذ كل مفتاح في سجلّ الرجوع واجهة NavKey. يعمل ذلك كواجهة علامات تشير إلى المكتبة بأنّه يمكن حفظ المفتاح.
  • استخدام التعليق التوضيحي @Serializable: بالإضافة إلى تنفيذ NavKey، يجب وضع التعليق التوضيحي @Serializable على الفئات والكائنات الرئيسية.

يوضّح المقتطف التالي عملية تنفيذ صحيحة للدالة rememberNavBackStack:

@Serializable
data object Home : NavKey

@Composable
fun NavBackStack() {
    val backStack = rememberNavBackStack(Home)
}

تذكُّر سجلّ الخلفية مع الأنواع الفرعية من NavKey

تعرض الدالة القابلة للإنشاء rememberNavBackStack عنصر NavBackStack<NavKey>. إذا كان تطبيقك يحدّد نوعًا فرعيًا خاصًا به من NavKey ترث منه جميع مفاتيحه، يمكنك الحفاظ على هذا النوع من خلال تنفيذ دالة تذكُّر مخصّصة، كما يلي:

@Serializable
sealed interface MyAppNavKey : NavKey

@Serializable
data object ScreenA: MyAppNavKey

@Serializable
data class ScreenB(val id: String): MyAppNavKey

@Composable
fun rememberMyAppNavBackStack(vararg elements: MyAppNavKey): NavBackStack<MyAppNavKey> {
    return rememberSerializable(serializer = serializer()) {
        NavBackStack(*elements)
    }
}

@Composable
fun MyApp() {
    // defaultNavBackStack is NavBackStack<NavKey>
    val defaultNavBackStack = rememberNavBackStack(ScreenA)
    // myAppNavBackStack is NavBackStack<MyAppNavKey>
    val myAppNavBackStack = rememberMyAppNavBackStack(ScreenA)
}

للاطّلاع على المزيد من الأمثلة، بما في ذلك كيفية التعامل مع تعدد الأشكال المفتوح، يُرجى الرجوع إلى NavBackStackSamples.

بديل: التخزين في ViewModel

هناك طريقة أخرى لإدارة سجلّ الرجوع، وهي تخزينه في ViewModel. للحفاظ على البيانات عند إيقاف العملية نهائيًا عند استخدام ViewModel أو أي مساحة تخزين مخصّصة أخرى، عليك اتّباع الخطوات التالية:

  • التأكّد من إمكانية تسلسل مفاتيح التنقّل: كما هو الحال مع rememberNavBackStack، يجب أن تكون مفاتيح التنقّل قابلة للتسلسل.
  • التعامل مع التسلسل والتحويل إلى تنسيق آخر يدويًا: أنت المسؤول عن حفظ التمثيل المتسلسل لكل مفتاح يدويًا في مساحة التخزين الثابتة (مثل SharedPreferences أو قاعدة بيانات أو ملف) وتحويله إلى تنسيق آخر منها عندما ينتقل تطبيقك إلى الخلفية أو تتم استعادته.

تحديد نطاق ViewModel مثيل إلى NavEntry كائن

تُستخدَم ViewModels للاحتفاظ بالحالة ذات الصلة بواجهة المستخدم عند حدوث تغييرات في الإعدادات، مثل تدوير الشاشة. تكون ViewModels تلقائيًا ضمن نطاق أقرب ViewModelStoreOwner، والذي يكون عادةً Activity أو Fragment.

ومع ذلك، قد تحتاج إلى تحديد نطاق ViewModel ليقتصر على NavEntry معيّن (أي شاشة أو وجهة معيّنة) في حزمة الخلف، بدلاً من Activity بأكمله. ويضمن ذلك الاحتفاظ بحالة ViewModel فقط عندما يكون NavEntry المعيّن جزءًا من سجلّ الرجوع، ويتم محوها عند إزالة NavEntry.

توفّر مكتبة الإضافات androidx.lifecycle:lifecycle-viewmodel-navigation3 NavEntryDecorator تسهّل ذلك. يوفّر هذا العنصر الزخرفي ViewModelStoreOwner لكل NavEntry. عند إنشاء ViewModel داخل محتوى NavEntry (على سبيل المثال، باستخدام viewModel() في Compose)، يتم تلقائيًا تحديد نطاق ViewModel ليطابق مفتاح NavEntry المحدّد في سجلّ الرجوع. وهذا يعني أنّه يتم إنشاء ViewModel عند إضافة NavEntry إلى سجلّ الرجوع، ويتم محوه عند إزالته.

لاستخدام NavEntryDecorator لتحديد نطاق ViewModels إلى NavEntrys، اتّبِع الخطوات التالية:

  1. أضِف الاعتمادية androidx.lifecycle:lifecycle-viewmodel-navigation3 إلى ملف app/build.gradle.kts.
  2. أضِف rememberSaveableStateHolderNavEntryDecorator() التلقائي إلى قائمة entryDecorators عند إنشاء NavDisplay.
  3. أضِف rememberViewModelStoreNavEntryDecorator() إلى قائمة entryDecorators.

NavDisplay(
    entryDecorators = listOf(
        // Add the default decorators for managing scenes and saving state
        rememberSaveableStateHolderNavEntryDecorator(),
        // Then add the view model store decorator
        rememberViewModelStoreNavEntryDecorator()
    ),
    backStack = backStack,
    entryProvider = entryProvider { },
)