Kotlin学习笔记系列:http://blog.csdn.net/column/details/16696.html
委托属性
kotlin提供了将属性委托到一个类的方法,就是委托属性。
当我们使用属性的get和set方法时,属性委托的getValue和setValue就会被调用。
属性委托的结构如下:
class Delegate : ReadWriteProperty{
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){
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() : ReadWriteProperty = NotNullSingle() //NotNullSingle是我们自定义的委托
}