美文网首页Kotlin学习笔记
kotlin学习笔记——委托属性

kotlin学习笔记——委托属性

作者: chzphoenix | 来源:发表于2017-09-28 14:30 被阅读88次

    Kotlin学习笔记系列:http://blog.csdn.net/column/details/16696.html

    委托属性

    kotlin提供了将属性委托到一个类的方法,就是委托属性。
    当我们使用属性的get和set方法时,属性委托的getValue和setValue就会被调用。
    属性委托的结构如下:

    class Delegate<T> : ReadWriteProperty<Any?, T>{  
         override fun getValue(thisRef: Any?, property: KProperty<*>): T{  
              return ...  
         }  
      
         override fun setValue(thisRef: Any?, property: KProperty<*>, value: T){  
              ...  
         }  
    }  
    

    其中T是委托属性的类型,getValue接收一个类的引用和一个属性的元数据,setValue多接收一个设置的值。

    使用by关键字来委托属性,如下:

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

    一、标准委托
    kotlin标准库中有一系列标准委托,我们可以直接使用,可以应付大部分情况。当然我们也可以自定义委托。

    1、Lazy
    需要提供一个lambda,当第一次执行getValue时会执行这个lambda进行初始化,之后再调用getValue会返回同一个值。所以委托的属性可以延迟进行初始化,在真正使用前可以不必初始化。如:

    class App : Application{  
         val database: SQLiteOpenHelper by lazy{  
              MyDatabaseHelper(applicationContext)  
         }  
      
         override fun onCreate(){  
              super.onCreate()  
              var db = database.writableDatabase  
         }  
    }  
    

    所以只要当在onCreate中使用时才去初始化,而这时候applicationContext已经存在了。
    lazy是线程安全的。如果不担心多线程问题,可以使用lazy(LazyThreadSafeMode.NONE){ ... }来提高性能
    同时要注意委托lazy的属性必须是不可变变量,既val修饰,如果用var修饰会报编译错误。

    2、Observable
    这个委托会检测值的变化,当属性的set方法被调用,会自动执行我们指定的lambda表达式。一旦属性被赋予了新值,我们就会接收到被委托的属性、旧值和新值。如:

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

    这个例子中一旦值被修改就会保存到数据库中。
    注意Delegates.observable("")中传的是设定的初始值

    3、Vetoable
    这是一个特殊的Observable,通过指定的lambda表达式来确定是否保存新值。如

    var name by Delegates.vetoable(0){  
         d, old, new -> new >= 0  
    }  
    

    例子中表示只有新值是正数时才保存

    4、NotNull
    有时候使用属性前可能未初始化,比如像activity这类无法在构造函数中初始化属性的情况。通常我们会定义一个可为null的变量并初始化为空,在每次使用之前做判空。kotlin中还有另外一种方法,使用委托属性NotNull,如:
    var name: String by Delegates.notNull()
    如果赋值前使用时会抛出一个错误。
    (目前这个方案与初始化为Null一样都在使用前要进行判断,否则抛出错误,所以不太能get到使用的点在哪里)

    5、从Map中委托值
    可以将属性委托到一个map,属性的值会从map中获取,属性的名字对应map中的key。
    注意不同版本的区别
    在有的版本中,需要import kotlin.properties.getValue 或 kotlin.properties.setValue
    在kotlin-stdlib:1.1.2-4中则不需要,但是不能直接使用map,如:

    class Config (map: HashMap<String, Any?>){  
      var name: String by map  
      var id: Int by map  
    }  
      
    var config = Config(hashMapOf(  
         "name" to "test",  
         "id" to 12  
    ))  
    

    二、自定义委托
    参照文章开始
    自定义委托必须实现ReadWriteProperty或ReadOnlyProperty,取决于被委托对象是var还是val。
    然后重写setValue和getValue方法即可。
    使用时可以直接使用(参考文章开始)
    也可以像Delegates那样集中定义函数,如:

    object DelegatesExt{  
         fun notNullSingle<T>() : ReadWriteProperty<Any?, T> = NotNullSingle()   //NotNullSingle是我们自定义的委托  
      
    }  
    

    相关文章

      网友评论

        本文标题:kotlin学习笔记——委托属性

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