تطوير Android / المتوسط: الحالة والبيانات والميزات الشاملة / الدرس 8
Room وDataStore والبيانات الدائمة
اختر التخزين بحسب شكل البيانات واحتياجات الاتساق، ثم احفظ سجلات المستخدم بالمعاملات وتطوير المخطط.
في هذه الصفحة
أهداف الدرس
- افصل السجلات العلائقية عن الإعدادات الصغيرة.
- اشرح المعاملات والترحيلات والاستعلامات القابلة للمراقبة.
طابق التخزين مع الشرط المطلوب
تملك قائمة القراءة سجلات متعددة ومعرّفات ثابتة واستعلامات وربما علاقات، فتناسبها قاعدة علائقية. يضيف Room وصولاً ذا أنواع وفحصاً للاستعلامات فوق SQLite. يلائم DataStore الإعدادات الصغيرة أو الضبط ذي النوع الذي يحدث باتساق، مثل ترتيب الفرز المفضل. لا تزامن أي منهما البيانات بين الأجهزة تلقائياً. تناسب الملفات المحتوى الثنائي الكبير، ويمكن للقاعدة حفظ بياناته الوصفية وملكيته. حدّد ما يجب صموده أمام وفاة العملية والتحديث والخروج واستعادة النسخ الاحتياطي قبل اختيار المكان أو وعد المستخدم بالدوام.
عرّف السجلات والوصول معاً
يستخدم المقتطف عائلة واجهات androidx.room الشائعة في مشروعات Room 2. اختر سلسلة مكتبة مثبتة ومتوافقة وإعداد compiler وKSP المطابق، ولا تخلط استيراداتها مع عائلة إصدار رئيسي مختلف في وثائق أحدث. يحدد الكيان الأعمدة المخزنة وتحدد DAO العمليات المسموحة. يصدر الاستعلام المراقب عند تغير الجداول المعنية، فتتبع الواجهة الحقيقة الدائمة. أبقِ التحقق الخاص بالمجال خارج تحويل SQL الخام واستخدم مستودعاً ليقرر تحول قيم القاعدة إلى حالة شاشة.
@Entity(tableName = "reading_items")
data class ReadingEntity(
@PrimaryKey val id: String,
val title: String,
val finished: Boolean
)
@Dao
interface ReadingDao {
@Query("SELECT * FROM reading_items ORDER BY title, id")
fun observeAll(): Flow<List<ReadingEntity>>
@Upsert
suspend fun save(item: ReadingEntity)
}
استورد تعليقات androidx.room وFlow من kotlinx.coroutines.flow. يجب أن يدعم إصدار Room المختار Upsert. أضف صنف RoomDatabase الذي يدرج الكيان وDAO واضبط تنفيذه المولّد واحقن DAO؛ لا يمثل المقتطف إعداد قاعدة كاملة.
احمِ التغييرات متعددة الخطوات
تجعل المعاملة مجموعة عمليات قاعدة البيانات تنجح أو تفشل معاً. مثلاً يجب أن يكون تعليم سجل بالتغيير وإضافة عملية مزامنة معلقة ذريين، وإلا ترك التعطل تعديلاً لا يُرفع أبداً. لا توفر coroutine ذرية قاعدة البيانات بذاتها. تجنب إبقاء المعاملات مفتوحة أثناء اتصالات الشبكة لأن التأخير البعيد غير محدود والأقفال تؤثر في القراء والكتّاب المحليين. اقرأ الحالة المحلية المطلوبة ونفذ العمل البعيد خارج المعاملة ثم طبّق النتيجة المتحقق منها بمعاملة قصيرة وسياسة تعارض صريحة.
احتفظ بمخزن إعدادات واحد لكل ملف
يمثل Preferences DataStore مفاتيح وقيماً دون مخطط علائقي. أعلن نسخته مرة واحدة في نطاق مناسب واكشف الإعدادات عبر مستودع. يحدث تحويل edit التفضيلات ذرياً فيتجنب قراءة وكتابة منفصلتين غير متزامنتين. يمكن ربط المفتاح المفقود بقيمة افتراضية موثقة، لكن خطأ الإدخال والإخراج حالة مختلفة ينبغي ألا تمحو قصد المستخدم بصمت. لا تنشئ نسخ DataStore فعالة متعددة للملف نفسه. إذا احتاجت الإعدادات علاقات أو تحديثات جزئية متكررة للسجلات، فأعد النظر في كون القاعدة تجريداً أفضل.
val Context.readingSettings by preferencesDataStore(name = "reading_settings")
private val SORT_BY_TITLE = booleanPreferencesKey("sort_by_title")
suspend fun setTitleSort(context: Context, enabled: Boolean) {
context.readingSettings.edit { values ->
values[SORT_BY_TITLE] = enabled
}
}
استخدم اعتماد datastore-preferences واستيرادات Context وpreferencesDataStore وbooleanPreferencesKey وedit. احتفظ بهذا المفوض في ملف واحد واستدعِه عبر مستودع إعدادات محقون على نطاق التطبيق. لا تعلن دالة suspend الاكتمال إلا بعد اكتمال عملية edit.
عامل الترحيلات كتغييرات في بيانات المستخدم
قد يحتاج تغيير الكيان زيادة إصدار المخطط وترحيلاً يحفظ السجلات القائمة. صدّر المخططات واختبر قاعدة قديمة فعلية تُرقى للإصدار الجديد مع القيم الافتراضية والقيود. قد يناسب الإنشاء المدمر بيانات مخبأة قابلة للاستبدال، لكنه لا يصلح إصلاحاً عابراً لسجلات المستخدم المهمة. قد تعيد النسخ الاحتياطية بيانات من إصدارات سابقة، فلا يكفي اختبار التثبيت الجديد. تحقق من ترتيب الاستعلام صراحة وأضف معياراً ثابتاً لكسر التعادل عندما تعتمد الواجهة أو الصفحات على ترتيب قابل للتكرار.
الأخطاء الشائعة وإصلاحها
يفقد تغيير المخطط السجلات المحفوظة
- لماذا يحدث؟
- حل الإنشاء المدمر محل ترحيل مطلوب.
- كيف تصلحه؟
- استعد من نسخة اختبار آمنة ونفذ ترحيلاً يحفظ البيانات.
- كيف تتجنب تكراره؟
- اختبر مسارات الترقية قبل توزيع تغييرات المخطط.
يستبدل كاتبا إعدادات تغييرات بعضهما
- لماذا يحدث؟
- تخالف القراءة والكتابة المنفصلتان أو النسخ المكررة ملكية المخزن.
- كيف تصلحه؟
- استخدم مخزناً واحداً وتحويل تحديثه الذري.
- كيف تتجنب تكراره؟
- وحّد إنشاء المخزن واختبر التحديث المتزامن.
تتوقف الواجهة أثناء الوصول للقاعدة
- لماذا يحدث؟
- يعمل استعلام حاجب على الخيط الرئيسي.
- كيف تصلحه؟
- استخدم واجهات DAO المدعومة من suspend أو Flow والتوزيع المناسب.
- كيف تتجنب تكراره؟
- اجعل المستودعات آمنة للرئيسي وتجنب تعطيل حمايات الخيوط.
اختبر فهمك
1. صنّف السمة المفضلة وعشرة آلاف سجل قراءة وصور الأغلفة المنزلة بحسب التخزين.
اعرض الحل المشروح
ينتمي تفضيل السمة الصغير إلى DataStore. تنتمي السجلات القابلة للاستعلام إلى Room بسياسة ترحيل. تنتمي الصور لملفات أو تخزين مخبأ مناسب مع بيانات وصفية في القاعدة عند الحاجة. حدّد هل هي مخبأ قابل لإعادة الإنشاء أم محتوى فريد لأن ذلك يغير توقعات التنظيف والنسخ الاحتياطي.
2. يستخدم حفظ عنوان وإدراج رفعه كتابتين مستقلتين. أوجد نافذة التعطل وأصلح العقد.
اعرض الحل المشروح
يترك التعطل بعد كتابة العنوان وقبل إدراج الطابور بيانات غير متزامنة دون سجل عمل. خزّن التعديل والعملية المعلقة في معاملة قاعدة واحدة. يستطيع المجدول اكتشاف العمليات لاحقاً، فلا يمحو الانقطاع بين تثبيت القاعدة والجدولة النية الدائمة.
أهم ما تعلمته
- تتبع خيارات التخزين شكل البيانات ومتطلبات التعافي.
- الدوام الذري منفصل عن تنفيذ coroutines.
- تحمي اختبارات الترحيل المستخدمين الحاليين إلى جانب التثبيت الجديد.