تطوير Android / المتقدم: أنظمة محمولة وإصدارات موثوقة / الدرس 13
البنية واستعادة العملية
صمّم حدود الميزات وعقود التعافي كي تعيد عملية منشأة بناء مهمة مستخدم متماسكة من مدخلات محفوظة صغيرة وبيانات دائمة.
في هذه الصفحة
أهداف الدرس
- عرّف مصادر الحقيقة واتجاه الاعتماديات.
- أعد بناء حالة الشاشة بعد وفاة العملية التي يبدأها النظام.
اجعل المسؤوليات ظاهرة
تعطي البنية القابلة للتوسع مسؤوليات مميزة للواجهة والوصول للبيانات وقواعد الأعمال. تعرض الواجهة الحالة وترسل الأحداث، وتنسق المستودعات مصادر البيانات، وتغلف عمليات مجال اختيارية القواعد المعقدة القابلة لإعادة الاستخدام. أضف طبقة مجال عندما توضح السلوك لا كغلاف آلي لكل قراءة. تتجه الاعتماديات نحو عقود تعبّر عن الاحتياجات لا نحو الأنشطة أو تنفيذات الشبكة. تفرض الوحدات الحدود والملكية لكن الإفراط في التقسيم يزيد كلفة البناء والتنقل. ابدأ بحد ميزة ذي معنى واستخرج البنية عندما يُفهم عقدها.
اختر مرجعاً واحداً لكل جزء من الحالة
قد تكون قاعدة البيانات مصدر الحقيقة للسجلات المؤكدة، بينما يحمل SavedStateHandle استعلام بحث عابراً يلزم لإعادة بناء الشاشة. استجابة الشبكة مدخل لتلك الحقيقة وليست مخبأ واجهة منافساً يملكه كل عنصر مستقلاً. عرّف كيف تصبح التعديلات معتمدة وكيف تمثل الإخفاقات. يمكن إعادة بناء حالة الشاشة المشتقة من سجلات دائمة ومعاملات صغيرة. يجعل الاحتفاظ بقائمة قابلة للتعديل ثانية في النشاط التعافي والمزامنة ملتبسين لأن النسختين قد تختلفان دون سياسة تحسم المرجع.
class SearchViewModel(
private val saved: SavedStateHandle,
private val repository: SearchRepository
) : ViewModel() {
val query: StateFlow<String> = saved.getStateFlow("query", "")
fun changeQuery(value: String) { saved["query"] = value }
val results: StateFlow<List<Book>> = query
.flatMapLatest { repository.observeMatches(it) }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), emptyList())
}
interface SearchRepository { fun observeMatches(query: String): Flow<List<Book>> }
استخدم واجهات الحالة المحفوظة في lifecycle وKotlin Flow؛ قد يتطلب flatMapLatest التصريح الذي يحدده إصدار coroutines المختار. Book نموذج المجال من درس الشبكات. وفّر مصنع ViewModel يراعي الحالة المحفوظة أو تكامل حقن حتى يشارك المقبض في الاستعادة.
احفظ مدخلات إعادة البناء
الحالة المحفوظة وسيلة تعاف خفيفة مرتبطة بعقد النظام لاستعادة المهمة. ليست تخزيناً دائماً ولا تضمن الاستعادة بعد الإيقاف الإجباري أو إزالة المهمة أو كل خروج يبدأه المستخدم. احفظ معرّفات ومرشحات وقيماً بسيطة للمسودة، وتجنب مجموعات كاملة وكائنات ثنائية كبيرة. لا تصمد نسخة ViewModel نفسها أمام وفاة العملية. عند إعادة البناء تحقق من المعاملات مقابل البيانات والمصادقة الحاليتين فقد يكون سجل حُذف أو حساب تغير منذ التقاط الحالة.
احقن الاعتماديات عند جذر التركيب
ينشئ جذر التركيب البنية على نطاق التطبيق ويوفر عقوداً أصغر لمالكي الميزات. يمنع ذلك البحث عن كائنات عامة قابلة للتعديل أو إنشاء قاعدة جديدة بكل شاشة. استخدم مصنعاً أو تكامل حقن يفهم ملكية ViewModel والحالة المحفوظة. يفيد المصنع اليدوي لـ ViewModel بلا متطلبات حالة محفوظة كما أدناه. لا تعِد استخدامه لمنشئ SavedStateHandle السابق دون مسار إضافات الإنشاء أو الحالة المحفوظة المدعوم؛ وإلا قد تُترجم الشيفرة منفردة وتختفي الاستعادة بصمت.
class ShelfFactory(private val repository: ShelfRepository) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
require(modelClass.isAssignableFrom(ShelfViewModel::class.java))
@Suppress("UNCHECKED_CAST")
return ShelfViewModel(repository) as T
}
}
استورد ViewModel وViewModelProvider واستخدم عقد المستودع من درس Flow. يقتصر التحويل المفحوص على المصنع. احصل على النسخة عبر مالك ViewModel الصحيح؛ فالاستدعاء المباشر المتكرر للمصنع يتجاوز الاحتفاظ المدار بالمالك.
اختبر إعادة الإنشاء كرحلة مستخدم
يختبر التدوير إعادة إنشاء النشاط مع احتمال استمرار العملية، فلا يثبت التعافي من وفاتها. استخدم بيئة Android اختبارية مضبوطة لوضع المهمة بالخلفية وإعادة إنشاء عمليتها بأدوات مدعومة واستئنافها دون خلط ذلك بالإيقاف الإجباري. تحقق من الاختيار وسياسة المسودة ومحتوى القاعدة وحالة العمليات المعلقة. كرر مع سجل محذوف أو جلسة منتهية. اجعل البديل المتوقع صريحاً كي لا تعيد الاستعادة محتوى غير مصرح أو تتظاهر باكتمال عملية في الذاكرة لمجرد ظهور رسالة نجاح سابقاً.
الأخطاء الشائعة وإصلاحها
ينجح التدوير وتفشل استعادة العملية
- لماذا يحدث؟
- عاشت المدخلات اللازمة في نسخة ViewModel فقط.
- كيف تصلحه؟
- احفظ مدخلات إعادة البناء الصغيرة والعمل المهم بصورة دائمة.
- كيف تتجنب تكراره؟
- افصل اختبارات إعادة الإنشاء عن وفاة العملية.
تعرض التفاصيل المستعادة محتوى حساب آخر
- لماذا يحدث؟
- وُثقت الهوية المحفوظة دون تفويض حالي.
- كيف تصلحه؟
- أعد التحقق من نطاق الحساب قبل تحميل السجل.
- كيف تتجنب تكراره؟
- ضمّن الخروج وتبديل الحساب في حالات الاستعادة.
تنشئ كل شاشة نسخة قاعدة إضافية
- لماذا يحدث؟
- يحدث إنشاء البنية داخل عرض الميزة.
- كيف تصلحه؟
- أنشئ البنية المشتركة في نطاق تطبيق مناسب.
- كيف تتجنب تكراره؟
- راجع المنشئات وملكية الاعتماديات.
اختبر فهمك
1. يوجد معرّف تفاصيل محفوظ لكن صفه اختفى. أي مصدر يحسم وماذا تعرض الاستعادة؟
اعرض الحل المشروح
يحسم التخزين الحالي المصرح. المعرّف طلب لإعادة بناء المهمة وليس إثباتاً لصحة السجل. اعرض عدم وجود مع خيار تنقل آمن وأزل الاختيار القديم عند الملاءمة. لا تعِد إنشاء سجل محذوف من لقطة واجهة قديمة.
2. يقترح فريق حفظ نتائج البحث كاملة في SavedStateHandle. استبدل التصميم.
اعرض الحل المشروح
احفظ الاستعلام الصغير والمرشح أو المعرّف المناسب. أعد بناء النتائج من المستودع الذي يوفر مصدره الدائم السجلات الحالية. احفظ تمييز التحميل أو الحالة المخبأة أثناء البناء. يقلل ذلك الحجم ويتجنب استعادة DTO قديم كأنه سجل مجال معتمد.
أهم ما تعلمته
- مصادر الحقيقة والأعمار قرارات بنيوية.
- تعيد الحالة المحفوظة بناء المهمة من مدخلات صغيرة.
- يجب أن يعيد التعافي التحقق من البيانات الحالية ونطاق الحساب.