DataStore: ما هو، أساسيات تخزين البيانات واستبدال SharedPreferences

المؤلف: IT Sectr نُشر: 2026-03-12 وقت القراءة: 9 دق

DataStore هو مكون من مكتبة Jetpack مصمم لتخزين كميات صغيرة من البيانات في تطبيقات Android. على عكس SharedPreferences، فهو يعمل بشكل غير متزامن ويضمن اتساق البيانات تحت الوصول المتزامن. وفقًا لـGoogle، 2024، يستخدم DataStore Kotlin Coroutines و Flow، مما يجعله آمنًا للخيط الرئيسي ومناسبًا للهندسات المعمارية التفاعلية.

النقاط الرئيسية

  • DataStore — بديل لـ SharedPreferences مع واجهة برمجة تطبيقات غير متزامنة وأنواع بيانات عبر Protocol Buffers
  • Preferences DataStore — مخزن بسيط من نوع مفتاح-قيمة مع قراءة عبر Flow ومعاملات
  • Proto DataStore — تخزين مقيد الأنواع مع ترحيلات تلقائية للمخطط
  • SharedPreferences — واجهة برمجة تطبيقات متزامنة تحجب خيط واجهة المستخدم مع الأحجام الكبيرة
  • الترحيل يتم من خلال واجهة SharedPreferencesMigration الخاصة دون فقدان البيانات

ما هو DataStore؟

DataStore هو حل من Google للتخزين المحلي للبيانات في Android، تم تقديمه في 2020 كبديل لـ SharedPreferences. يدعم وضعين: Preferences DataStore (أزواج بسيطة من مفتاح-قيمة) و Proto DataStore (مخطط مقيد الأنواع يعتمد على Protocol Buffers).

الميزة الرئيسية هي التزامن الكامل: جميع عمليات القراءة ترجع Flow من Kotlin Coroutines، ويتم تنفيذ الكتابة في سياق coroutine. هذا يلغي حظر الخيط الرئيسي، الذي كان مشكلة نموذجية لـ SharedPreferences عند التعامل مع كميات كبيرة من البيانات.

يضمن DataStore ذرية العمليات: الكتابات المتزامنة لا تؤدي إلى فقدان البيانات بفضل نموذج المعاملات الخاص به. إذا قام مكونان بتعديل نفس القيمة في وقت واحد، يتعامل DataStore مع التعارض بشكل صحيح من خلال آلية compare-and-swap.

وفقًا لـ Google I/O 2023، يُستخدم DataStore في 40% من مشاريع Android الجديدة، وتوصي Google بالترحيل من SharedPreferences في جميع التطبيقات التي تتطلب استقرار تخزين الإعدادات.

هندسة DataStore

في قلب DataStore يوجد SingleProcessDataStore — تنفيذ يعمل ضمن عملية واحدة. يستخدم تخزينًا قائمًا على الملفات مع تأمين على مستوى الملف: عند كتابة البيانات، يتم تأمين الملف، مما يمنع التلف تحت الوصول المتزامن.

يتعامل DataStore تلقائيًا مع أخطاء إلغاء التسلسل: إذا كان الملف تالفًا، فإنه يعيد قيمة افتراضية ويعيد كتابة الملف. هذا السلوك قابل للتكوين عبر corruptionHandler، الذي يمكن تعيينه عند إنشاء DataStore.

مشاكل SharedPreferences التي يحلها DataStore

يعاني SharedPreferences من ثلاث مشاكل أساسية: القراءة المتزامنة من القرص على الخيط الرئيسي، وعدم وجود ضمانات للذرية في الكتابات المتزامنة، وعدم القدرة على تتبع التغييرات بشكل تفاعلي. يحل DataStore الثلاثة: Flow للمراقبة، وتأمين الملفات للذرية، وواجهة برمجة تطبيقات غير متزامنة لأمان الخيوط.

كيف يعمل DataStore في Android؟

يخزن DataStore البيانات في ملفات على وحدة التخزين الداخلية للجهاز. يستخدم Preferences DataStore تنسيق ملف مشابه لـ SharedPreferences ولكن مع بيانات تعريف إضافية للتحقق من السلامة. يستخدم Proto DataStore تنسيق Protocol Buffers الثنائي، مما يقلل حجم الملف ويسرع التسلسل.

عند قراءة البيانات، يقوم DataStore بتحميل الملف بأكمله في الذاكرة مرة واحدة، وبعد ذلك يتلقى المشتركون الحالة الحالية عبر Flow. يتم بث التغييرات إلى جميع المشتركين النشطين تلقائيًا — لا يلزم تسجيل مستمعين يدويًا، كما في SharedPreferences.

كيف يعمل Preferences DataStore

يستخدم Preferences DataStore آلية تسلسل مدمجة تعتمد على Map. كل إدخال هو زوج من سلسلة نصية ونوع بدائي (Int, Boolean, Float, Long, String, Set). يتم تخزين البيانات في ملف XML، مشابه لـ SharedPreferences، ولكن مع كتابة ذرية من خلال تأمين الملف.

مثال على إنشاء Preferences DataStore: امتداد preferencesDataStore على Context ينشئ singleton باسم الملف. عند الاستدعاءات المتكررة، يتم إرجاع نفس المثيل — وهذا يلغي تكرار الملفات والارتباك بين مثيلات التخزين المختلفة.

كيف يعمل Proto DataStore

يتطلب Proto DataStore تعريف مخطط بيانات من خلال ملف .proto وتجميعه باستخدام إضافة protobuf. يتم استخدام فئة Java المُنشأة كنقطة دخول واحدة لجميع الحقول — وهذا يلغي الأخطاء المطبعية في المفاتيح، الشائعة مع SharedPreferences.

يتم تعريف مخطط Proto DataStore مرة واحدة ويدعم إضافة حقول جديدة دون فقدان البيانات القديمة. إذا أضاف إصدار جديد من التطبيق حقلاً بقيمة افتراضية، فسيتم إلغاء تسلسل الملف القديم بشكل صحيح — التوافق مع الإصدارات السابقة مدمج في البروتوكول.

Preferences DataStore و Proto DataStore: مقارنة

يعتمد الاختيار بين Preferences DataStore و Proto DataStore على تعقيد البيانات ومتطلبات التنميط. كلا الخيارين غير متزامنين ومعاملاتيين، لكنهما يختلفان في أمان الأنواع وأداء التسلسل.

الخاصيةPreferences DataStoreProto DataStore
التنميطضعيف (مفتاح-قيمة)قوي (فئة مولدة)
التسلسلXML (مدمج)Protocol Buffers (protobuf)
حجم الملفكبير (XML قابل للقراءة)صغير (ثنائي)
التعقيدمنخفض (بدون .proto)متوسط (يتطلب .proto)
ترحيل المخططلا يوجد مخططتلقائي (proto)
التوافقSharedPreferences (عبر الترحيل)Proto DataStore فقط

متى تختار Preferences DataStore

Preferences DataStore مناسب للإعدادات البسيطة: أعلام تفعيل الميزات، سلسلة رمز التفويض، عدد مرات تشغيل التطبيق. إذا كانت البيانات قليلة (حتى 10–15 مفتاحًا) ولا تتطلب مخططًا صارمًا، فإن Preferences DataStore يوفر حد أدنى للدخول دون توصيل إضافة protobuf.

متى تختار Proto DataStore

Proto DataStore مبرر عندما يكون هيكل البيانات معقدًا أو قد يتغير بين إصدارات التطبيق. على سبيل المثال، إعدادات ملف تعريف المستخدم أو تكوين اختبار A/B مع 20+ حقلاً. يوفر Protobuf تنميطًا قويًا وترحيلات تلقائية، مما يلغي أخطاء وقت التشغيل بسبب عدم تطابق المفاتيح.

كيفية الترحيل من SharedPreferences إلى DataStore

توفر Google آلية ترحيل مدمجة من خلال فئة SharedPreferencesMigration. يتم الترحيل مرة واحدة عند التشغيل الأول بعد تحديث التطبيق: يقرأ DataStore البيانات من SharedPreferences، ويكتبها في تنسيقه الخاص، ويضع علامة على اكتمال الترحيل.

يدعم الترحيل تحويلات مخصصة: إذا كانت المفاتيح في SharedPreferences لا تتطابق مع مفاتيح DataStore المرغوبة، يمكنك تحديد دالة تحويل عبر SharedPreferencesMigration. يتيح ذلك إعادة تسمية المفاتيح وتغيير أنواع البيانات أثناء الترحيل.

الترحيل خطوة بخطوة

أولاً، أضف DataStore إلى build.gradle وأنشئ مثيل DataStore مع الترحيل: SharedPreferencesMigration يقبل اسم ملف SharedPreferences ومجموعة من المفاتيح المراد نقلها. ثانيًا، أزل جميع التعليمات البرمجية التي تعمل عبر SharedPreferences واستبدلها باستدعاءات DataStore. ثالثًا، اختبر الترحيل: عند التشغيل الأول، يجب أن تظهر البيانات في DataStore، ويجب ألا يُستخدم ملف SharedPreferences القديم بعد الآن.

kotlin
val Context.dataStore by preferencesDataStore(
    name = "settings",
    produceMigrations = { context ->
        listOf(
            SharedPreferencesMigration(context, "old_prefs")
        )
    }
)

أمثلة استخدام DataStore في الكود

يتكامل DataStore بسهولة مع المشروع الحالي. فيما يلي أمثلة عملية لـ Preferences DataStore و Proto DataStore — كلاهما يوضح القراءة والكتابة والمراقبة التفاعلية للبيانات.

Preferences DataStore: قراءة وكتابة الإعدادات

في هذا المثال، يخزن Preferences DataStore ثلاثة إعدادات: المظهر الداكن واسم المستخدم وعدد مرات التشغيل. تتم القراءة من خلال امتداد .data، الذي يعيد Flow. تتم الكتابة من خلال دالة التعليق .edit، التي تضمن ذرية التغييرات.

kotlin
val Context.settingsDataStore by preferencesDataStore(name = "settings")

val isDarkMode: Flow<Boolean> = settingsDataStore.data
    .map { preferences ->
        preferences[booleanPreferencesKey("dark_mode")] ?: false
    }

suspend fun toggleDarkMode() {
    settingsDataStore.edit { prefs ->
        val current = prefs[booleanPreferencesKey("dark_mode")] ?: false
        prefs[booleanPreferencesKey("dark_mode")] = !current
    }
}

Proto DataStore: المخطط والاستخدام

يتطلب Proto DataStore تعريف ملف .proto. بعد التجميع، يتم إنشاء فئة UserSettings تُستخدم للقراءة والكتابة. يتم وصف ترحيلات إصدار المخطط في نفس ملف .proto ويتم تطبيقها تلقائيًا.

kotlin
// user_preferences.proto
syntax = "proto3";

message UserPreferences {
    string display_name = 1;
    int32 notification_count = 2;
    bool notifications_enabled = 3;
}

// القراءة من DataStore
val userPreferencesFlow: Flow<UserPreferences> =
    protoDataStore.data

// كتابة قيم جديدة
suspend fun updateDisplayName(name: String) {
    protoDataStore.updateData { prefs ->
        prefs.toBuilder()
            .setDisplayName(name)
            .build()
    }
}

المراقبة التفاعلية للتغييرات

يتكامل DataStore مع هندسة MVVM عبر ViewModel. يتم جمع Flow من DataStore عبر .stateIn واستخدامه في واجهة المستخدم. مع كل تغيير في البيانات، يتم تحديث واجهة المستخدم تلقائيًا — لا حاجة لتحديثات يدوية أو LiveData.

kotlin
class SettingsViewModel(
    private val dataStore: DataStore<Preferences>
) : ViewModel() {

    val uiState: StateFlow<SettingsUiState> =
        dataStore.data
            .map { prefs ->
                SettingsUiState(
                    isDarkMode = prefs[booleanPreferencesKey("dark_mode")] ?: false,
                    counter = prefs[intPreferencesKey("launch_count")] ?: 0
                )
            }
            .stateIn(
                scope = viewModelScope,
                started = SharingStarted.WhileSubscribed(5000),
                initialValue = SettingsUiState()
            )
}

الأسئلة الشائعة

كيف يختلف DataStore عن SharedPreferences؟

DataStore يعمل بشكل غير متزامن (لا يحجب خيط واجهة المستخدم)، ويدعم الوصول المتزامن من خلال المعاملات، ويسمح بالاشتراك التفاعلي للتغييرات عبر Flow. SharedPreferences هو واجهة برمجة تطبيقات متزامنة مع خطر ANR مع كميات كبيرة من البيانات وبدون دعم تفاعلي مدمج.

هل يمكن استخدام DataStore مع Java؟

DataStore مكتوب بلغة Kotlin ويتطلب Kotlin Coroutines. استخدامه من Java ممكن ولكنه غير مريح: ستحتاج إلى إنشاء أغلفة مع CompletableFuture أو إدارة coroutines يدويًا. لمشاريع Java، توصي Google بالاحتفاظ بـ SharedPreferences أو إضافة Kotlin إلى الوحدة.

هل DataStore مناسب لتخزين كميات كبيرة من البيانات؟

DataStore يقوم بتحميل الملف بأكمله في الذاكرة عند القراءة، لذلك فهو غير مناسب لتخزين القوائم أو الكائنات الكبيرة. لمثل هذه السيناريوهات، استخدم Room أو SQLite. DataStore محسّن للإعدادات والبيانات المنظمة الصغيرة — حتى مئات الكيلوبايتات.

كيفية معالجة خطأ ملف DataStore التالف؟

عند إنشاء DataStore، يمكنك تمرير corruptionHandler — دالة تُستدعى عند تلف الملف. افتراضيًا، يرمي DataStore استثناء CorruptionException. في corruptionHandler، يمكنك إعادة بيانات فارغة، وبعدها سيعيد DataStore كتابة الملف بحالة صحيحة.

هل يتطلب Proto DataStore ملف .proto؟

نعم، يتطلب Proto DataStore تعريف مخطط في ملف .proto وتوصيل إضافة protobuf-gradle-plugin. إذا كان المشروع صغيرًا والبيانات بسيطة، فمن الأسهل استخدام Preferences DataStore — فهو لا يتطلب تكوين بناء إضافي.

الخلاصة

  • DataStore — بديل حديث لـ SharedPreferences يعمل مع Kotlin Coroutines و Flow
  • Preferences DataStore — مفتاح-قيمة بسيط بدون مخطط، مناسب للإعدادات
  • Proto DataStore — تخزين مقيد الأنواع مع مخطط protobuf وترحيل تلقائي
  • الترحيل من SharedPreferences مدمج في DataStore عبر SharedPreferencesMigration
  • أمان الخيوط — جميع العمليات غير متزامنة، تم إلغاء حظر واجهة المستخدم
  • التفاعلية — Flow يخطر المشتركين عند كل تغيير في البيانات
  • توصية — استخدم DataStore في جميع مشاريع Android الجديدة، وقم بترحيل المشاريع الحالية عند العمل مع الإعدادات

سنقوم بتطوير تطبيق جوال جاهز

تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا