Android kotlin 委托

作者: NiceDream | 来源:发表于2017-06-16 08:53 被阅读77次

    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()
    }
    }
    

    相关文章

      网友评论

        本文标题:Android kotlin 委托

        本文链接:https://www.haomeiwen.com/subject/hmepqxtx.html