本文已同步发表于我的
微信公众号
,搜索代码说
即可关注,欢迎与我沟通交流。
写在前面
Kotlin
中的委托机制是一种非常灵活的语言特性,它可以让我们将对象的某些属性或方法委托给其他对象来处理。常见的有类委托
、属性委托
,详细用法参见:Kotlin | 10分钟搞定by委托机制。
注:本文不再详细讲解委托机制是什么,如果还不了解什么是委托机制,可以点击上文中的链接学习。
本文是 by
委托机制的实践,利用委托机制来对SharedPreference
(以下简称sp
)进行封装,从而简化其使用,默认 sp
的存取数据方式如下:
SharedPreference
存数据:
//获得SharedPreferences的实例 sp_name是文件名
val sp: SharedPreferences = getSharedPreferences("sp_name", Context.MODE_PRIVATE)
//获得Editor 实例
val editor: SharedPreferences.Editor = sp.edit()
//以key-value形式保存数据
editor.putString("data_key", "data")
//apply()是异步写入数据
editor.apply()
//commit()是同步写入数据
//editor.commit()
SharedPreference
取数据:
//获得SharedPreferences的实例
val sp = getSharedPreferences("sp_name", MODE_PRIVATE)
//通过key值获取到相应的data,如果没取到,则返回后面的默认值
val data = sp.getString("data_key", "defaultValue")
通常项目中我们会封装成类似 SPUtil
的方式使用,但是 sp
使用起来还是稍显麻烦,下面就利用 by
委托机制对 sp
进行更优雅的封装。
利用委托机制封装SharedPreference
/**
* SharedPreferences委托代理
* @param context Context
* @param spName SP存入的XML名字
* @param defaultValue 默认值
* @param key 存取数据时对应的key
*/
class SharedPreferencesDelegate<T>(
private val context: Context,
private val spName: String,
private val defaultValue: T,
private val key: String? = null,
) : ReadWriteProperty<Any?, T> {
private val sp: SharedPreferences by lazy(LazyThreadSafetyMode.NONE) {
context.getSharedPreferences(spName, Context.MODE_PRIVATE)
}
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
val finalKey = key ?: property.name
return when (defaultValue) {
is Int -> sp.getInt(finalKey, defaultValue)
is Long -> sp.getLong(finalKey, defaultValue)
is Float -> sp.getFloat(finalKey, defaultValue)
is Boolean -> sp.getBoolean(finalKey, defaultValue)
is String -> sp.getString(finalKey, defaultValue)
is Set<*> -> sp.getStringSet(finalKey, defaultValue as? Set<String>)
else -> throw IllegalStateException("Unsupported type")
} as T
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
val finalKey = key ?: property.name
with(sp.edit()) {
when (value) {
is Int -> putInt(finalKey, value)
is Long -> putLong(finalKey, value)
is Float -> putFloat(finalKey, value)
is Boolean -> putBoolean(finalKey, value)
is String -> putString(finalKey, value)
is Set<*> -> putStringSet(finalKey, value.map { it.toString() }.toHashSet())
else -> throw IllegalStateException("Unsupported type")
}
apply()
}
}
}
使用它:
class CommonPreferences(context: Context) {
companion object {
/**
* 通过传入不同的SP文件名来存储到不同的XML中
*/
const val FIR_SP_NAME = "FIR_SP_NAME" //文件名1
const val SEC_SP_NAME = "SEC_SP_NAME"//文件名2
}
var isShow by SharedPreferencesDelegate(context, FIR_SP_NAME, false, "key_is_show")
//这里没有用key值,则会默认使用属性名来当做key值
var name by SharedPreferencesDelegate(context, FIR_SP_NAME, "")
var age by SharedPreferencesDelegate(context, SEC_SP_NAME, 0, "key_age")
//这里没有用key值,则会默认使用属性名来当做key值
var cost by SharedPreferencesDelegate(context, SEC_SP_NAME, 0.0f)
}
上述代码展示了根据不同的文件名把数据存入到不同的XML
文件中,你可以根据自己的需求进行调整。在 Activity
中进行存取值:
private val spInfo = CommonPreferences(this)
//存值
spInfo.isShow = true
spInfo.name = "小马快跑"
//存值
spInfo.age = 18
spInfo.cost = 123.4f
spInfo.setString = setOf("一", "二", "三")
//取值
log("isShow -> ${spInfo.isShow}, name -> ${spInfo.name}")
log("age -> ${spInfo.age}, cost -> ${spInfo.cost},setString -> ${spInfo.setString}")
可以看到对sp
的存取值简直不要太简单,跟对象属性的存取似的,来看执行结果:
E/TTT: isShow -> true, name -> 小马快跑
E/TTT: age -> 18, cost -> 123.4,setString -> [一, 三, 二]
取值成功了,那么存值呢?看下手机对应目录下是否有存入的数据:
嗯,存取值都成功了。
总结
主要利用的是属性委托val/var <属性名>: <类型> by <表达式>
,例如:
var isShow by SharedPreferencesDelegate(context, FIR_SP_NAME, false, "key_is_show")
通过属性代码执行到 SharedPreferencesDelegate
中的逻辑进行存取操作,不必再关心整个的存取细节,nice!
欢迎扫描下方二维码
或搜索微信公众号 代码说
, 关注我的微信公众号查看最新文章~