在Kotlin中,委托属性(Delegated Properties)是一种强大的语言特性,允许你将属性的 getter 和 setter 方法的实现委托给其他对象。这使得你能够通过委托来重用代码、将属性的行为解耦,并实现一些通用的模式。下面是一些关键概念和用法:
class Example { var property: String by Delegate() } class Delegate { operator fun getValue(thisRef: Any?, property: KProperty<*>): String { // 获取属性值的实际实现 return "Delegated value" } operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) { // 设置属性值的实际实现 println("Setting value to: $value") } }
在上面的代码中,Example类中的property属性的访问,比如,访问example.property,就会委托到Delegate.getValue; 属性值的设置example.property = "str",就会委托到
Delegae.setValue。
实际例子:
fun saveCookie(url: String?, domain: String?, cookies: String) { url ?: return var spUrl: String by Preference(url, cookies) @Suppress("UNUSED_VALUE") spUrl = cookies domain ?: return var spDomain: String by Preference(domain, cookies) @Suppress("UNUSED_VALUE") spDomain = cookies }
var spUrl: String by Preference(url, cookies),定义一个委托属性spUrl,Preference委托,执行spUrl = cookies,会将这个setValue的动作委托到Preference类中的setValue。
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) { putSharedPreferences(name, value) }
其中value的值是cookies.如果要访问spUrl,那么,对应的getValue方法,会被委托到Preference中的getValue方法中去。
总结来说:
委托属性,就是将一个属性的getValue方法和setValue方法委托到另外一个代理类来实现。将属性的获取和设置隔离开来。
class Preference<T>(val name: String, private val default: T) { companion object { private val file_name = "wan_android_file" private val prefs: SharedPreferences by lazy { App.context.getSharedPreferences(file_name, Context.MODE_PRIVATE) } /** * 删除全部数据 */ fun clearPreference() { prefs.edit().clear().apply() } /** * 根据key删除存储数据 */ fun clearPreference(key: String) { prefs.edit().remove(key).apply() } /** * 查询某个key是否已经存在 * * @param key * @return */ fun contains(key: String): Boolean { return prefs.contains(key) } /** * 返回所有的键值对 * * @param context * @return */ fun getAll(): Map<String, *> { return prefs.all } } operator fun getValue(thisRef: Any?, property: KProperty<*>): T { return getSharedPreferences(name, default) } operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) { putSharedPreferences(name, value) } @SuppressLint("CommitPrefEdits") private fun putSharedPreferences(name: String, value: T) = with(prefs.edit()) { when (value) { is Long -> putLong(name, value) is String -> putString(name, value) is Int -> putInt(name, value) is Boolean -> putBoolean(name, value) is Float -> putFloat(name, value) else -> putString(name, serialize(value)) }.apply() } @Suppress("UNCHECKED_CAST") private fun getSharedPreferences(name: String, default: T): T = with(prefs) { val res: Any = when (default) { is Long -> getLong(name, default) is String -> getString(name, default) ?: "" is Int -> getInt(name, default) is Boolean -> getBoolean(name, default) is Float -> getFloat(name, default) else -> deSerialization(getString(name, serialize(default)) ?: "") } return res as T } /** * 序列化对象 * @param person * * * @return * * * @throws IOException */ @Throws(IOException::class) private fun <A> serialize(obj: A): String { val byteArrayOutputStream = ByteArrayOutputStream() val objectOutputStream = ObjectOutputStream( byteArrayOutputStream ) objectOutputStream.writeObject(obj) var serStr = byteArrayOutputStream.toString("ISO-8859-1") serStr = java.net.URLEncoder.encode(serStr, "UTF-8") objectOutputStream.close() byteArrayOutputStream.close() return serStr } /** * 反序列化对象 * @param str * * * @return * * * @throws IOException * * * @throws ClassNotFoundException */ @Suppress("UNCHECKED_CAST") @Throws(IOException::class, ClassNotFoundException::class) private fun <A> deSerialization(str: String): A { val redStr = java.net.URLDecoder.decode(str, "UTF-8") val byteArrayInputStream = ByteArrayInputStream( redStr.toByteArray(charset("ISO-8859-1")) ) val objectInputStream = ObjectInputStream( byteArrayInputStream ) val obj = objectInputStream.readObject() as A objectInputStream.close() byteArrayInputStream.close() return obj } }