تعرض هذه المقالة مثالًا على إنشاء مفوض لـ SharedPreferences ، مما يقلل من مستوى اللمعان ويجعل استخدام SharedPrefernces أكثر ملاءمة. أولئك الذين يرغبون في رؤية النتيجة يمكنهم الذهاب إلى حل جاهز.
واحدة من المهام الملحة للتنمية لالروبوت هو حفظ أي بيانات بين الدورات. الطرق الرئيسية لهذا: تخزين على الخادم أو في الملفات على الجهاز القابل للتنفيذ. إحدى الطرق الأولى التي يستطيع أي مطور أندرويد مبتدئ من خلالها معرفة ذلك هو تخزينه في ملف باستخدام أداة SharedPreferences الجاهزة.
دعنا نقول أننا بحاجة إلى تسجيل اسم المستخدم ومن ثم عرضه في مكان ما في التطبيق.
class UserStore(private val preferences: SharedPreferences) { fun getUserName(): String? { return preferences.getString(USER_NAME, "") } fun saveUserName(userName: String) { preferences.edit().putString(USER_NAME, userName).apply() } companion object { private const val USER_NAME = "user_name" } }
ما هو المندوب وكيف يتم إعداده
باختصار ، هذه فئة تلخص الإعداد والحصول على خاصية. الذي يريد أن يعرف المزيد من الوثائق الرسمية .
لجعل الفصل مفوضًا ، يجب تطبيق واجهة ReadOnlyProperty لـ val و ReadWriteProperty لـ var. نعبر SharedPreferences ، المفتاح الذي سيتم به تخزين الخاصية والقيمة الافتراضية من خلال المنشئ. في setValue ، اضبط القيمة على getValue واحصل على القيمة.
class StringPreferencesDelegate( private val preferences: SharedPreferences, private val name: String, private val defValue: String ) : ReadWriteProperty<Any?, String?> { override fun setValue(thisRef: Any?, property: KProperty<*>, value: String?) { preferences.edit().putString(name, value).apply() } override fun getValue(thisRef: Any?, property: KProperty<*>): String? { return preferences.getString(name, defValue) } }
تطبيق مندوب
class UserStore(private val preferences: SharedPreferences) { var userName: String by StringPreferencesDelegate(preferences, USER_NAME, "") companion object { private const val USER_NAME = "user_name" } }
يتم التعيين إلى خاصية المفوض بواسطة الكلمة الأساسية. الآن ، في كل مرة يتم فيها طلب هذه الخاصية أو تعيينها ، سيتم إطلاق أساليب getValue و setValue للمفوض الذي تم إنشاؤه.
يمكن فعل الشيء نفسه مع الحقول الأخرى ، على سبيل المثال ، إذا كنت تريد حفظ هاتف المستخدم بنفس الطريقة.
var userPhone: String by StringPreferencesDelegate(preferences, USER_PHONE, "")
عام
من أجل عدم عمل مفوض منفصل لكل نوع بيانات ، نستخدم تعميمات الوثائق الرسمية العامة .
عادةً ما يحدث التعارف اللاشعوري الأول عند إنشاء مثيل لفئة القائمة. لذلك ، يتم تحديد نوع البيانات المحدد الذي يعمل به.
val names :List<String> = listOf("Jon","Bob","Max")
لتحديد نوع بيانات معمم لفئة ما بعد اسمه ، يجب عليك تحديد اسم هذا المتغير بين أقواس زاوية.
PreferencesDelegate<TValue>(...)
تحتاج الآن إلى تحديد أن القيمة المحددة والقيمة الافتراضية من النوع TValue.
class PreferencesDelegate<TValue>( val preferences: SharedPreferences, private val name: String, private val defValue: TValue ) : ReadWriteProperty<Any?, TValue> { override fun getValue(thisRef: Any?, property: KProperty<*>): TValue { ... } override fun setValue(thisRef: Any?, property: KProperty<*>, value: TValue) { ... } }
وفقًا لذلك ، يبدو إنشاء مثيل للفئة الآن كما يلي:
var userName: String? by StringPreferencesDelegate<String?>(...)
يبقى القيام بإجراء تعيين للحصول على الخصائص وتعيينها ، فنحن نحدد نوع البيانات عن طريق delaultValue ، وفي الوقت نفسه يعطي مجموعة ذكية من هذه القيمة لنوع البيانات المحدد ، وإذا حدث خطأ ما ولم تكن الخاصية من نوع TValue ، فإننا نرجع defValue.
override fun getValue(thisRef: Any?, property: KProperty<*>): TValue { with(preferences) { return when (defValue) { is Boolean -> (preferences.getBoolean(name, defValue) as? TValue) ?: defValue ... } } } override fun setValue(thisRef: Any?, property: KProperty<*>, value: TValue) { with(preferences.edit()) { when (value) { is Boolean -> putBoolean(name, value) ... } apply() } }
مع أنواع البيانات الأخرى هو مشابه.
خطأ مخصص
يبقى السؤال ما يجب القيام به مع الفرع الآخر ، لأن نوع TValue يمكن أن يكون أي شيء على الإطلاق.
من الجيد أن ترتكب خطأً مخصصًا. إذا حدث استثناء ، فسيكون واضحًا ما حدث.
class NotFoundRealizationException(value: Any?) : Exception("not found realization for ${value?.javaClass}") ... else -> throw NotFoundRealizationException(value) ...
استنتاج
في المجموع ، نحصل على مفوض جاهز للاستخدام:
@Suppress("UNCHECKED_CAST") class PreferencesDelegate<TValue>( val preferences: SharedPreferences, private val name: String, private val defValue: TValue ) : ReadWriteProperty<Any?, TValue> { override fun getValue(thisRef: Any?, property: KProperty<*>): TValue { with(preferences) { return when (defValue) { is Boolean -> (getBoolean(name, defValue) as? TValue) ?: defValue is Int -> (getInt(name, defValue) as TValue) ?: defValue is Float -> (getFloat(name, defValue) as TValue) ?: defValue is Long -> (getLong(name, defValue) as TValue) ?: defValue is String -> (getString(name, defValue) as TValue) ?: defValue else -> throw NotFoundRealizationException(defValue) } } } override fun setValue(thisRef: Any?, property: KProperty<*>, value: TValue) { with(preferences.edit()) { when (value) { is Boolean -> putBoolean(name, value) is Int -> putInt(name, value) is Float -> putFloat(name, value) is Long -> putLong(name, value) is String -> putString(name, value) else -> throw NotFoundRealizationException(value) } apply() } } class NotFoundRealizationException(defValue: Any?) : Exception("not found realization for $defValue") }
مثال التطبيق
class UserStore(private val preferences: SharedPreferences) { var userName: String by PreferencesDelegate(preferences, USER_NAME, "") var userPhone: String by PreferencesDelegate(preferences, USER_PHONE, "") var isShowLicence: Boolean by PreferencesDelegate(preferences, USER_LICENCE, false) companion object { private const val USER_NAME = "user_name" private const val USER_PHONE = "user_phone" private const val USER_LICENCE = "user_licence" } }