توضّح الأقسام التالية استراتيجيات لحفظ سجلّ الرجوع وتخزين الحالة المرتبطة بالإدخالات في سجلّ الرجوع.
حفظ سجلّ الرجوع
للحصول على تجربة مستخدم جيدة، من الضروري التأكّد من استمرار حالة التنقّل في تطبيقك خلال أحداث مراحل النشاط المختلفة، بما في ذلك تغييرات الإعدادات وإيقاف العملية. في 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، اتّبِع الخطوات التالية:
- أضِف الاعتمادية
androidx.lifecycle:lifecycle-viewmodel-navigation3إلى ملفapp/build.gradle.kts. - أضِف
rememberSaveableStateHolderNavEntryDecorator()التلقائي إلى قائمةentryDecoratorsعند إنشاءNavDisplay. - أضِف
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 { }, )