تخزين البيانات باستخدام SharedPreferences
تخزين البيانات باستخدام SharedPreferences
تحتاج كل تطبيقات Android تقريبًا إلى تذكّر شيء ما بين الجلسات: هل أكمل المستخدم الإعداد الأولي (Onboarding)، وما السمة التي اختارها، ورمز المصادقة، أو آخر استعلام بحث أدخله. SharedPreferences هو مخزن المفتاح-القيمة المدمج في Android لهذا النوع تحديدًا من البيانات الخفيفة والمستمرة. يخزّن الأنواع الأولية والسلاسل النصية في ملف XML على التخزين الداخلي للجهاز، ويبقى محفوظًا عبر توقف العمليات وإعادة تشغيل الجهاز، ولا يستلزم أي كود إعداد مسبق.
ما هو SharedPreferences (وما ليس عليه)
تخيّل SharedPreferences كخريطة مكتوبة بأنواع محددة تُحفظ تلقائيًا على القرص. وهو يدعم ستة أنواع من القيم: String، وint، وlong، وfloat، وboolean، وSet<String>. هذا هو نطاقه بالكامل. إنه ليس قاعدة بيانات علائقية، ولا مخزنًا للملفات، ولا مناسبًا للبيانات الكبيرة أو المنظمة. إذا احتجت إلى تخزين أكثر من عشرات أزواج المفتاح-القيمة، أو كانت البيانات تحمل علاقات، فاستخدم Room (الدرس الثالث).
/data/data/<اسم.الحزمة>/shared_prefs/<اسم_الملف>.xml. وهو خاص بتطبيقك ولا تستطيع التطبيقات الأخرى قراءته. الملف غير مشفّر بشكل افتراضي، لذا لا تخزّن كلمات المرور أو الرموز الحساسة هنا دون حماية إضافية.
الحصول على كائن SharedPreferences
هناك طريقتان للحصول على كائن SharedPreferences. الأولى هي getSharedPreferences(name, mode) التي تتيح لك تسمية الملف. والثانية هي getPreferences(mode) المتاحة فقط داخل Activity، وتستخدم اسم فئة النشاط كاسم للملف.
مرّر دائمًا Context.MODE_PRIVATE وضعًا للوصول. الأوضاع الأخرى (MODE_WORLD_READABLE، MODE_WORLD_WRITEABLE) أُهملت في API 17 وأُزيلت في API 24 لأنها ثغرات أمنية. MODE_PRIVATE هو الخيار الآمن الوحيد.
قراءة القيم
كل دالة get في SharedPreferences تأخذ مفتاحًا وقيمة افتراضية تُعاد عندما لا يكون المفتاح موجودًا. أمدّ دائمًا بقيمة افتراضية منطقية — فذلك يُلغي الحاجة إلى فحوصات null ويُوضّح نية الكود.
كتابة القيم باستخدام Editor
لا يمكنك الكتابة مباشرةً من خلال كائن SharedPreferences. بدلًا من ذلك، تفتح Editor، وتُجري تغييراتك، ثم تُثبّتها. هذا التصميم القائم على المعاملات يضمن أن تغييراتك إما تصل كلها إلى القرص أو لا يصل منها شيء.
apply() على الذاكرة المؤقتة فورًا وتُجدول الكتابة على القرص في خيط خلفي. أما commit() فتُوقف الخيط الحالي حتى تكتمل الكتابة على القرص وتُعيد قيمة منطقية تُشير إلى النجاح. استخدم apply() على الخيط الرئيسي في الغالبية العظمى من الحالات. استخدم commit() فقط حين تحتاج فعلًا للتأكد من وصول البيانات للقرص قبل المتابعة — مثلًا، قبيل احتمال توقّف العملية في عملية حرجة.
يمكنك أيضًا ربط استدعاءات المحرر (Editor) في نمط Fluent:
حذف البيانات ومسحها
الاستماع للتغييرات
تحتاج واجهة المستخدم أحيانًا للتفاعل عند تغيير تفضيل — مثل التبديل بين الثيم الفاتح والداكن. سجّل OnSharedPreferenceChangeListener وألغِ تسجيله عند تدمير المكوّن لتجنّب تسرّب الذاكرة.
SharedPreferences المستمعين في WeakHashMap. إذا مرّرت دالة لامبدا مجهولة أو متغيرًا محليًا، فقد يُجمعه محصّل garbage collector فورًا ويتوقف مستمعك عن العمل بصمت. احفظ المستمع دائمًا كحقل في الفئة أو نفّذ الواجهة مباشرةً على Activity/Fragment كما هو مبيّن أعلاه.
نمط عملي: فئة مساعدة للتفضيلات
توزيع مفاتيح السلاسل النصية السحرية عبر فئات متعددة يُشكّل خطر صيانة. ضمّ كل وصول إلى التفضيلات في فئة مساعدة مخصصة حتى تُعرَّف المفاتيح مرة واحدة ولا يرى المستدعون السلاسل النصية الخام أبدًا.
يتفاعل المستدعون فقط مع دوال ذات أنواع واضحة ولا يعرفون شيئًا عن مفاتيح السلاسل النصية الداخلية.
متى تستخدم SharedPreferences
- تفضيلات المستخدم — السمة، اللغة، إعدادات الإشعارات.
- أعلام الجلسة — هل رأى المستخدم شاشة Onboarding، هل هو مسجّل الدخول.
- القيم المؤقتة البسيطة — آخر مدينة في تطبيق الطقس، آخر تبويب مختار.
- أجزاء صغيرة من حالة التطبيق — معرّف المستخدم، عدد صحيح للتفضيل.
لا تستخدمه لـ: مجموعات البيانات الكبيرة، قوائم الكائنات، البيانات الثنائية، أو أي شيء يستفيد من الاستعلامات. لهذه الحالات، Room هو الأداة المناسبة.
الخلاصة
يوفّر SharedPreferences مخزن مفتاح-قيمة بسيطًا ودائمًا مدعومًا بملف XML. احصل على كائن منه بـ getSharedPreferences("name", Context.MODE_PRIVATE)، اقرأ القيم بدوال get المكتوبة بأنواع تقبل قيمًا افتراضية، واكتب عبر Editor مُنهيًا بـ apply(). أبعد مفاتيح السلاسل النصية عن المستدعين بتغليف التفضيلات في فئة مساعدة مخصصة. في الدرس القادم ستنتقل إلى SQLite للبيانات التي تحتاج إلى بنية وقابلية للاستعلام.