Android(Kotlin) 委托(by) 封装 SharedPreferences

在 Kotlin 中,委托是一种通过将自身的某个功能交给另一个对象来实现代码重用的技术。通过委托,我们可以将某个属性或方法的实现委托给另一个对象,从而减少重复代码的编写。委托可以用于实现多重继承、代码复用和扩展现有类的功能。 Kotlin 中的委托通过关键字 “by” 来实现。委托分为两种:类委托和属性委托。

类委托是将接口的实现委托给另一个类,属性委托是将属性的实现委托给另一个对象。

本文讲解的是使用自定义属性委托来封装 SharedPreferences 的使用


var field by EntrustClass()

这就是比较常见的属性委托了,调用字段 field get()/set() 会对应到委托类 EntrustClass 的 getValue()/setValue()。举个例子:

class EntrustClass(private var name: String) {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        println("调用了getValue() === $name")
        return name
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        println("调用了setValue() === $value")
        name = value
    }
}

fun main() {
    var field by EntrustClass("张三")
    field            // 调用了 get()
    field = "李四"    // 调用了 set()
}

Run main:
调用了getValue() === 张三
调用了setValue() === 李四

在第一行属性 field 委托给了类 EntrustClass,字段类型是与委托类 getValue() 的返回值类型相同的

当 field 进行 get()/set() 操作时,就会执行委托类的 getValue()/setValue() 逻辑


这样子就可以把一些冗余的代码操作(比如 SharedPreferences)使用(by)进行封装:

String 类型:

class SpString(private val spName: String, val key: String, private val defValue: String = "") {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        val sp = context.getSharedPreferences(spName, Context.MODE_PRIVATE)
        return sp.getString(key, defValue)!!
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        val sp = context.getSharedPreferences(spName, Context.MODE_PRIVATE)
        sp.edit().putString(key, value).apply()
    }
}

Boolean 类型:

class SpBoolean(private val spName: String, val key: String, private val defValue: Boolean = false) {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): Boolean {
        val sp = context.getSharedPreferences(spName, Context.MODE_PRIVATE)
        return sp.getBoolean(key, defValue)
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Boolean) {
        val sp = context.getSharedPreferences(spName, Context.MODE_PRIVATE)
        sp.edit().putBoolean(key, value).apply()
    }
}

其余的类型可以自行拓展


用法:

    private var spBooleanValue by SpBoolean(SP_NAME, "key1")
    private var spStringValue by SpString(SP_NAME, "key2")

    private fun getBooleanValue(): Boolean = spBooleanValue
    private fun getStringValue(): String = spStringValue

    private fun setSpValue(value: Boolean) {
        spBooleanValue = value
    }

    private fun setSpValue(value: String) {
        spStringValue = value
    }

直接在对象上 get 和 set 即可进行对 SharedPreferences 的读取和写入


在实际的开发当中,会在一个工具类当中进行 SharedPreferences 数据的读写,已经非常好了。但是若数据存储量非常大时,会使得工具类非常臃肿,使用委托封装可以进一步减少冗余代码