AndroidAndroid Kotlinkotlin

Android kotlin 委托

2017-06-16  本文已影响77人  NiceDream

1 类委托

interface Base {
    fun print()
}
class BaseImpl(val x: Int) : Base {
    override fun print() { print(x) }
}
class Derived(b: Base) : Base by b

fun main(args: Array<String>) {
    val b = BaseImpl(10)
    Derived(b).print() // 输出 10
}

Derived 的超类型列表中的 by句表示b 将会在 Derived 中内部存储。 并且编译器将成转发给 b 的所有 Base 的法。

2 委托属性

class Example {
    var p: String by Delegate()
}

语法是: val/var <属性名>: <类型> by <表达式>。

属性对应的 get()(和 set() )会被委托给表达式的getValue() 和 setValue()。

第一个参数是 p 所在对象的引用、第二个参数保存了对 p属性自身的描述;

class Delegate {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
    return "$thisRef, thank you for delegating '${property.name}' to me!"
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
    println("$value has been assigned to '${property.name} in $thisRef.'")
}
}

对于只读属性(即 val 声明的),委托必须提供名为 getValue 的函数,该函数接受以下参数:

thisRef 必须与属性所有者类型(对于扩展属性指被扩展的类型)相同或者是它的超类型。

property 必须是类型 KProperty<*>或其超类型。

这个函数必须返回与属性相同的类型(或其类型)。

对于可变属性(即 var 声明的),委托必须额外提供 setValue 的函数,该函数接受以下参数:

thisRef 同 getValue() ;

property 同 getValue() ;

new value 必须和属性同类型或者是它的超类型。

getValue() 或/和 setValue() 函数可以通过委托类的成员函数提供或者由扩展函数提供。 两函数都需要 operator 关键字来标记。

委托类可以实现包含所需 operator 方法的 ReadOnlyProperty 或 ReadWriteProperty。

这俩接口是在 Kotlin 标准库中声明的:

interface ReadOnlyProperty<in R, out T> {
    operator fun getValue(thisRef: R, property: KProperty<*>): T
}
interface ReadWriteProperty<in R, T> {
    operator fun getValue(thisRef: R, property: KProperty<*>): T
    operator fun setValue(thisRef: R, property: KProperty<*>, value: T)
}

3 延迟属性 Lazy

val lazyValue: String by lazy {
    "Hello"
}

延迟加载属性(lazy property): 属性值只在初次访问时才会计算;

get()会执行lambda表达式并记录结果,后续的get方法将只返回结果。

var类型属性不能设置为延迟加载属性,因为在lazy中并没有setValue(…)方法。

lazy操作符是线程安全的。如果在不考虑多线程问题或者想提高更多的性能,也可以使
用 lazy(LazyThreadSafeMode.NONE){ … } 。
在LazyThreadSafetyMode中声明了几种,[Lazy]实例在多个线程之间同步访问的形式:

SYNCHRONIZED:锁定,用于确保只有一个线程可以初始化[Lazy]实例。

PUBLICATION:初始化函数可以在并发访问未初始化的[Lazy]实例值时调用几次,,但只有第一个返回的值将被用作[Lazy]实例的值。

NONE:没有锁用于同步对[Lazy]实例值的访问; 如果从多个线程访问实例,是线程不安全的。此模式应仅在高性能至关重要,并且[Lazy]实例被保证永远不会从多个线程初始化时使用。

class App : Application() {
    val database: SQLiteOpenHelper by lazy {
        MyDatabaseHelper(applicationContext)
    }

    override fun onCreate() {
        super.onCreate()
        val db = database.writableDatabase
    }
}

4 可观察属性(Observable)

Delegates.observable() 函数接受两个参数:
第一个是初始化值,
第二个是属性值变化事件的响应器(handler).

这种形式的委托,采用了观察者模式,其会检测可观察属性的变化,当被观察属性的setter()方法被调用的时候,响应器(handler)都会被调用(在属性赋值处理完成之后)并自动执行执行的lambda表达式,同时响应器会收到三个参数:被赋值的属性, 赋值前的旧属性值, 以及赋值后的新属性值。


class ViewModel(val db: MyDatabase) {
    var myProperty by Delegates.observable("") {
        d, old, new ->
        db.saveChanges(this, new)
    }
}

5 Map中映射值
在像解析 JSON 或者做其他“动态”事情中。把map映射到属性

import kotlin.properties.getValue
class Configuration(map: Map<String, Any?>) {
    val width: Int by map
    val height: Int by map
    val dp: Int by map
    val deviceName: String by map
}

conf = Configuration(mapOf(
    "width" to 1080,
    "height" to 720,
    "dp" to 240,
    "deviceName" to "mydevice"
))

6 局部委托属性
你可以将局部变量声明为委托属性。
memoizedFoo 只有someCondition满足条件,第一调用才会初始化

fun example(computeFoo: () -> Foo) {
    val memoizedFoo by lazy(computeFoo)
    if (someCondition && memoizedFoo.isValid()) {
    memoizedFoo.doSomething()
}
}
上一篇 下一篇

猜你喜欢

热点阅读