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

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

حفظ سجلّ الأنشطة السابقة

يُعدّ ضمان استمرار حالة التنقّل في تطبيقك خلال أحداث مراحل النشاط المختلفة، بما في ذلك تغييرات الإعدادات وإيقاف العملية نهائيًا، أمرًا بالغ الأهمية لتقديم تجربة جيدة للمستخدم. في 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 { },
)