SharedPreferences هو مخزن بيانات من نوع مفتاح-قيمة على Android مصمم لحفظ الإعدادات البسيطة وتكوينات التطبيق. يتم تخزين البيانات في ملف XML على الجهاز وهي متاحة فقط داخل التطبيق الذي أنشأها. وفقًا للوثائق الرسمية Android Developers, 2025، يدعم SharedPreferences تخزين الأنواع البدائية: String وInt وBoolean وFloat وLong وSet<String>. هذا هو الحل الأبسط والأسرع لحفظ كميات صغيرة من إعدادات المستخدم دون الحاجة إلى استعلامات SQL أو العمل مع نظام الملفات مباشرة.
النقاط الرئيسية
SharedPreferences هي آلية مدمجة في Android لتخزين أزواج المفاتيح والقيم في ملف XML على وحدة التخزين الداخلية للجهاز. وهي متاحة منذ API Level 1 ولا تتطلب مكتبات إضافية. الغرض الرئيسي منها هو حفظ تفضيلات المستخدم وحالة الواجهة وإشارات التشغيل الأول وغيرها من البيانات البسيطة التي لا تتطلب قاعدة بيانات منظمة.
كل ملف SharedPreferences مرتبط باسم محدد ووضع وصول. افتراضيًا يُستخدم وضع Context.MODE_PRIVATE، الذي يقتصر الوصول إلى الملف على التطبيق الحالي فقط. سابقًا كان Android يدعم وضعي MODE_WORLD_READABLE وMODE_WORLD_WRITEABLE، لكنهما أصبحا مهملين منذ API Level 17 وتمت إزالتهما بالكامل في Android 7.0 (API 24) لأسباب أمنية.
على الرغم من بساطته، يُستخدم SharedPreferences في ملايين تطبيقات Android. وفقًا لـ Google، أكثر من 90% من التطبيقات المنشورة على Google Play تستخدم SharedPreferences لتخزين الإعدادات. ومع ذلك، للسيناريوهات المعقدة (كميات كبيرة من البيانات، أمان الأنواع، عدم التزامن) توصي Google بحلول أكثر حداثة مثل Preferences DataStore من مكتبة Android Jetpack.
فيزيائيًا، يتم تخزين SharedPreferences كملف XML في دليل التطبيق: /data/data/{package_name}/shared_prefs/{file_name}.xml. يحتوي الملف على عنصر جذر <map> مع عناصر فرعية <string> و<int> و<boolean> و<float> و<long> حسب نوع القيمة المخزنة. حجم الملف غير محدود، لكن للكميات الكبيرة من البيانات (أكثر من 100 كيلوبايت) يبدأ أداء القراءة والكتابة في الانخفاض الملحوظ.
ملفات SharedPreferences غير مشفرة افتراضيًا. يتم تخزين البيانات بنص واضح في نظام ملفات الجهاز. لتخزين البيانات الحساسة (الرموز، كلمات المرور) يُوصى باستخدام EncryptedSharedPreferences من مكتبة AndroidX Security، التي تقوم بتشفير المفاتيح والقيم تلقائيًا باستخدام AES256-GCM.
يعمل SharedPreferences على مبدأ التخزين المؤقت في الذاكرة مع مزامنة دورية على القرص. عند أول وصول إلى الملف (عبر getSharedPreferences)، يقوم Android بتحميل ملف XML إلى ذاكرة الوصول العشوائي وتحليله في كائن Map. تتم جميع عمليات القراءة اللاحقة من الذاكرة، دون إعادة القراءة من القرص. وهذا يضمن سرعة عالية في الوصول إلى البيانات.
تستخدم عمليات الكتابة Editor — وهو مخزن مؤقت داخلي للتغييرات. عندما يستدعي المطور putString أو putBoolean، يتم تخزين التغييرات في كائن Editor في الذاكرة. تحدث الكتابة الفعلية على القرص عند استدعاء طريقة commit (متزامن) أو apply (غير متزامن). حتى يتم استدعاء هذه الطرق، لا يتم حفظ البيانات، وفي حالة تعطل التطبيق بشكل غير متوقع، قد تُفقد التغييرات.
للحصول على مثيل SharedPreferences، تُستخدم طريقتان: getPreferences وgetSharedPreferences. الأولى متاحة فقط داخل Activity وتنشئ ملفًا باسم Activity. الثانية أكثر مرونة، تقبل اسم ملف ووضع وصول، وهي متاحة من أي سياق (Application، Activity، Service). يُوصى باستخدام getSharedPreferences مع اسم ملف يتوافق مع الوحدة أو وظيفة التطبيق.
// الحصول على SharedPreferences
val prefs = context.getSharedPreferences(
"user_settings", Context.MODE_PRIVATE
)
// كتابة البيانات
with(prefs.edit()) {
putString("username", "آنا")
putInt("age", 28)
putBoolean("isLoggedIn", true)
apply()
}
// قراءة البيانات
val username = prefs.getString("username", "")
val age = prefs.getInt("age", 0)
val isLoggedIn = prefs.getBoolean("isLoggedIn", false)
عند استخدام MODE_MULTI_PROCESS (مهمل)، تتم مزامنة SharedPreferences بين العمليات. ومع ذلك، لا تضمن هذه المزامنة الذرية، وتوصي Google بتجنب SharedPreferences في سيناريوهات العمليات المتعددة. لمثل هذه الحالات، من الأفضل استخدام ContentProvider أو Room مع وصول بين العمليات أو DataStore.
توفر SharedPreferences مجموعة من الطرق لقراءة البيانات حسب المفتاح وواجهة Editor للكتابة. كل طريقة قراءة تقبل معلمتين: مفتاح وقيمة افتراضية يتم إرجاعها إذا لم يتم العثور على المفتاح. تحدد القيمة الافتراضية أيضًا نوع القيمة المرجعة: getString يعيد String، وgetInt يعيد Int، وهكذا.
| طريقة القراءة | طريقة الكتابة | نوع البيانات |
|---|---|---|
| getString | putString | String |
| getInt | putInt | Int |
| getBoolean | putBoolean | Boolean |
| getFloat | putFloat | Float |
| getLong | putLong | Long |
| getStringSet | putStringSet | Set<String> |
Editor هو كائن داخلي لـ SharedPreferences يجمع التغييرات في مخزن مؤقت. بعد إجراء جميع التغييرات، يستدعي المطور commit() (كتابة متزامنة) أو apply() (كتابة غير متزامنة). الفرق جوهري: commit يمنع الخيط الحالي حتى اكتمال الكتابة على القرص ويعيد boolean (نجاح/فشل)، بينما apply ينفذ الكتابة في خلفية ويعيد التحكم فورًا لكنه لا يعيد نتيجة.
يُوصى باستخدام apply بدلاً من commit في جميع الحالات التي لا تحتاج فيها إلى معرفة نتيجة الكتابة. apply أسرع ولا يمنع خيط واجهة المستخدم. يجب استخدام commit فقط عندما يكون من الضروري معرفة ما إذا تم حفظ البيانات بنجاح، أو عند العمل مع وضع متعدد العمليات. لإزالة مفاتيح فردية، يُستخدم remove، للمسح الكامل — clear. جميع عمليات الحذف تتم أيضًا من خلال Editor.
// تغييرات متعددة - apply واحد
prefs.edit {
putString("theme", "dark")
putBoolean("notifications", false)
remove("old_key")
}
// مستمع تغيير القيمة
prefs.registerOnSharedPreferenceChangeListener { prefs, key ->
Log.d("TAG", "تغير المفتاح: $key")
}
بدءًا من Android 12 (API 31)، تم تحسين SharedPreferences بدعم registerOnSharedPreferenceChangeListener مع إلغاء الاشتراك التلقائي عبر Lifecycle. وهذا يساعد على تجنب تسرب الذاكرة المرتبط بالمستمعين المنسيين. في الإصدارات الأقدم، يجب على المطور استدعاء unregisterOnSharedPreferenceChangeListener يدويًا في onDestroy أو onStop للمكون.
على الرغم من انتشاره الواسع، فإن SharedPreferences ليس حلاً شاملاً لجميع سيناريوهات تخزين البيانات في Android. اعتمادًا على حجم البيانات ومتطلبات أمان الأنواع والأداء، توصي Google ببدائل متنوعة مضمنة في Android Jetpack والمكتبة القياسية لـ Android.
| الحل | متى تستخدم | العيوب |
|---|---|---|
| SharedPreferences | إعدادات صغيرة (حتى 100 مفتاح) | لا يوجد أمان للأنواع، قراءة متزامنة |
| DataStore | إعدادات متوسطة التعقيد مع coroutines | لا يوجد توافق عكسي أسفل API 14 |
| Room | بيانات منظمة وقوائم | مفرط لـ 3-5 إعدادات |
| EncryptedSharedPreferences | بيانات حساسة ورموز | اعتماد على AndroidX Security |
DataStore هي مكتبة Android Jetpack قدمتها Google كبديل لـ SharedPreferences. توفر نوعين: Preferences DataStore (مفتاح-قيمة، مثل SharedPreferences) وProto DataStore (تخزين بنوع محدد عبر Protocol Buffers). يستخدم DataStore coroutines و Flow للعمل غير المتزامن، ويضمن أمان الأنواع، ويتعامل تلقائيًا مع ترحيل الإصدارات. توصي Google بـ DataStore لجميع المشاريع الجديدة.
الميزة الرئيسية لـ DataStore هي عدم التزامن على مستوى API. جميع عمليات القراءة تعيد Flow، وعمليات الكتابة هي وظائف suspend. وهذا يلغي تمامًا حظر خيط واجهة المستخدم الذي قد يحدث مع القراءة المتزامنة لـ SharedPreferences. بالإضافة إلى ذلك، يضمن DataStore اتساق البيانات: تتم الكتابة في معاملة، وعند الفشل يتم التراجع عن جميع التغييرات.
لننظر في مثال عملي: إعدادات السمة (فاتح/داكن/النظام) في تطبيق Android. يختار المستخدم سمة، ويتم حفظ الاختيار في SharedPreferences. عند تشغيل التطبيق لاحقًا، يتم استعادة السمة من الإعدادات المحفوظة. للتحديث التفاعلي لواجهة المستخدم، يُستخدم مراقبة التغييرات عبر SharedPreferences.OnSharedPreferenceChangeListener.
لننشئ فئة ThemePreferences التي تغلف جميع الأعمال مع SharedPreferences للسمة. توفر الفئة طرق getTheme (قراءة) وsetTheme (كتابة) وobserveTheme (مراقبة). سيكون اسم ملف الإعدادات "app_preferences" مع وضع MODE_PRIVATE. للراحة، يتم وضع المفاتيح في كائن رفيق كثوابت.
class ThemePreferences(context: Context) {
companion object {
private const val PREF_NAME = "app_preferences"
private const val KEY_THEME = "theme_mode"
const val THEME_LIGHT = "light"
const val THEME_DARK = "dark"
const val THEME_SYSTEM = "system"
}
private val prefs = context
.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
fun getTheme(): String =
prefs.getString(KEY_THEME, THEME_SYSTEM) ?: THEME_SYSTEM
fun setTheme(theme: String) {
prefs.edit { putString(KEY_THEME, theme) }
}
fun observeTheme(callback: (String) -> Unit) {
prefs.registerOnSharedPreferenceChangeListener { _, key ->
if (key == KEY_THEME) {
callback.invoke(getTheme())
}
}
}
}
في Activity أو Fragment، يتم الحصول على مثيل ThemePreferences من خلال سياق التطبيق. عند التهيئة، يتم استدعاء getTheme لتعيين السمة الحالية. عندما يختار المستخدم سمة جديدة، يتم استدعاء setTheme، وعبر observeTheme يتم تحديث الواجهة دون إعادة تشغيل Activity. من المهم إلغاء الاشتراك من المستمع في onDestroy لمنع تسرب الذاكرة، خاصة إذا تم إعادة إنشاء Activity عند تغيير التكوين.
للتطبيقات ذات الإصدار الأدنى المستهدف Android 12+، يُوصى باستخدام registerOnSharedPreferenceChangeListener مع LifecycleObserver. وهذا يدير الاشتراك وإلغاء الاشتراك تلقائيًا عند تغيير دورة حياة المكون. للإصدارات الأقدم، يجب إدارة الاشتراك وإلغاء الاشتراك يدويًا، وهو مصدر متكرر للأخطاء في تطبيقات الإنتاج التي تستخدم SharedPreferences.
الأسئلة الشائعة
يدعم SharedPreferences بشكل مباشر الأنواع البدائية فقط وSet<String>. لتخزين الكائنات، يجب تسلسلها إلى سلسلة JSON عبر Gson أو Moshi، وحفظها عبر putString، وإلغاء تسلسلها عند القراءة. للكائنات المعقدة ذات الحقول المتعددة، يُوصى باستخدام Room بدلاً من SharedPreferences مع تسلسل JSON.
نعم، SharedPreferences آمن للخيوط. جميع عمليات القراءة والكتابة متزامنة على مستوى كائن SharedPreferences وEditor الخاص به. ومع ذلك، عند استخدام وضع متعدد العمليات، لا يتم ضمان المزامنة. للوصول المتزامن من خيوط متعددة داخل تطبيق واحد، SharedPreferences آمن بدون أقفال إضافية.
لمسح جميع البيانات بالكامل من SharedPreferences، استدعِ طريقة clear() على Editor وطبق التغييرات عبر apply. إذا كنت بحاجة إلى حذف ملف XML نفسه، استخدم deleteSharedPreferences(name) على السياق. مسح بيانات التطبيق عبر الإعدادات → التطبيقات → مسح البيانات يزيل أيضًا جميع ملفات SharedPreferences.
للمشاريع الجديدة، توصي Google بـ DataStore كبديل لـ SharedPreferences. يوفر DataStore عملاً غير متزامن مع coroutines، وأمان الأنواع (Proto DataStore)، وترحيلًا تلقائيًا. يجب اختيار SharedPreferences فقط للمشاريع ذات الإصدار الأدنى أقل من API 14 أو عند الحاجة إلى تكامل سريع بدون تبعيات إضافية.
لتشفير البيانات، استخدم EncryptedSharedPreferences من مكتبة AndroidX Security. تقوم بتشفير المفاتيح والقيم تلقائيًا باستخدام AES-256 GCM. عملية الإعداد ضئيلة: يتم استبدال getSharedPreferences بـ EncryptedSharedPreferences.create مع تحديد مفتاح رئيسي من Android Keystore.
الخلاصة
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.
اقرأ أيضًا