Delegates实现双击back退出
简介
说Delegates之前,首先必须了解下kotlin的委托机制
,这个委托机制还是很不错的,可以将一个对象的构造和设置值,都给委托给其它
委托机制
关键词by
,是不是很眼熟,这不是我们经常用过的by lazy{}
,没错懒加载就是用委托实现的
自定义委托
考大家一个问题val
和var
有啥区别吗?val
是不可变的变量,必须要在初始化化的时候赋值。var
是可变的变量。有没有考虑过为啥呢?
// 其实每个变量都有一个隐藏的方法,如果是val变量修饰,只有get方法
val name: String = ""
get() {
return field
}
// var 有get方法和set方法,当你给name2进行赋值的时候,set方法就会调用
var name2: String = ""
get() {
return field
}
set(value) {
}
来尝试来一个定义一个委托:
这里描述下,我现在是
val
定义变量,只需要ReadOnlyProperty
(只需要要委托getValue方法),我定义了一个value
变量记录值(初始化内容123),当使用这个变量的读取这个值的时候,就会调用我的委托方法
val name: String by object : ReadOnlyProperty<Any?, String> {
var value: String = "123"
override fun getValue(thisRef: Any?, property: KProperty<*>): String {
println("取这个[${property.name}]属性赋值:$value")
// 返回这个记录值
return value
}
}
// 同理var的委托定义,如果我这样写,当使用这个变量的读取这个值的时候,就会调用我的委托方法。当我设置值的时候就会调用我的set方法,会传入一个value方法。
var name2: String by object : ReadWriteProperty<Any?, String> {
var value: String = "123"
override fun getValue(thisRef: Any?, property: KProperty<*>): String {
println("取这个[${property.name}]属性赋值:$value")
// 返回这个记录值
return value
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
println("为这个[${property.name}]属性赋值:$value")
// 记录下当前这个值
this.value = "我是从新构造:$value"
}
}
这里有必要说下 thisRef 是个什么鬼?就是这个变量对应在那个对象中
曲线救国委托实现多继承
interface A {
fun call()
}
class B() : A {
override fun call() {
println("我调用call了")
}
}
open class D() {
fun core() {
println("我调用core了")
}
}
class C() : D(), A by B(){
fun test(){
// todo 我可以直接掉call 变向多继承(这个在协程的 协程上下文与调度器(5)--协程作用域(重点) 有用到)
call()
}
}
Delegates
Delegates.notNull
// 使用很简单
val name:String by Delegates.notNull<String>()
// 源码分析
// 第一句没啥的看下,NotNullVar
public fun <T : Any> notNull(): ReadWriteProperty<Any?, T> = NotNullVar()
// 是不是看出来了,在取值的时候,如果是null就会抛异常
private class NotNullVar<T : Any>() : ReadWriteProperty<Any?, T> {
private var value: T? = null
public override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return value ?: throw IllegalStateException("Property ${property.name} should be initialized before get.")
}
public override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
this.value = value
}
}
Delegates.observable
大家记住这个,用它可以完成双击back退出
val name: String by Delegates.observable("初始化值") { pre, old, new ->
log("以前的值$old 新设置的值$new")
}
看下源码:
ObservableProperty是关键,主要看委托的getValue方法和setValue方法
// 这里没啥好说的,主要看下 ObservableProperty对象
public inline fun <T> observable(initialValue: T, crossinline onChange: (property: KProperty<*>, oldValue: T, newValue: T) -> Unit):
ReadWriteProperty<Any?, T> =
object : ObservableProperty<T>(initialValue) {
// 注意这里重写了afterChange方法
// 这里是调用onChange方法,就是我们传入的lambda表达式
override fun afterChange(property: KProperty<*>, oldValue: T, newValue: T) = onChange(property, oldValue, newValue)
}
public abstract class ObservableProperty<T>(initialValue: T) : ReadWriteProperty<Any?, T> {
private var value = initialValue
protected open fun beforeChange(property: KProperty<*>, oldValue: T, newValue: T): Boolean = true
protected open fun afterChange(property: KProperty<*>, oldValue: T, newValue: T): Unit {}
public override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return value
}
// 主要是这里,
public override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
// 记录上一次的值
val oldValue = this.value
// beforeChange默认返回true,先不管
if (!beforeChange(property, oldValue, value)) {
return
}
// 为this.value设置新的值,为getValue做准备
this.value = value
// 调用afterChange方法,被重写了,所以会调用到onChange,是不是很简单
afterChange(property, oldValue, value)
}
}
Delegates.vetoable
这个能在设置值的时候,加逻辑判断,如果不满足便不更新值
val name: String by Delegates.vetoable("初始化值") { pre, old, new ->
// 如果设置的新值是a开头的就设置新值,返回ture就修改,false就不修改
new.startsWith("a")
}
源码分析:
其实这里和observable
差不多,但是注意重写的是beforeChange
方法
public inline fun <T> vetoable(initialValue: T, crossinline onChange: (property: KProperty<*>, oldValue: T, newValue: T) -> Boolean):
ReadWriteProperty<Any?, T> =
object : ObservableProperty<T>(initialValue) {
// 注意这里重写的是beforeChange方法
override fun beforeChange(property: KProperty<*>, oldValue: T, newValue: T): Boolean = onChange(property, oldValue, newValue)
}
接下来就和以前差不多了
public abstract class ObservableProperty<T>(initialValue: T) : ReadWriteProperty<Any?, T> {
private var value = initialValue
protected open fun beforeChange(property: KProperty<*>, oldValue: T, newValue: T): Boolean = true
protected open fun afterChange(property: KProperty<*>, oldValue: T, newValue: T): Unit {}
public override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return value
}
// 主要是这里,
public override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
// 记录上一次的值
val oldValue = this.value
// 主要看这里
// beforeChange写了,如果我们的lamabda表达式返回的ture就不会return,就会调用后面的赋值方法
if (!beforeChange(property, oldValue, value)) {
return
}
// 为this.value设置新的值,为getValue做准备
this.value = value
// 调用afterChange方法,被重写了,所以会调用到onChange,是不是很简单
afterChange(property, oldValue, value)
}
}
实践完成双击back退出
其实很简单,就是使用observable的特性
private var backPressedTime by Delegates.observable(0L) { pre, old, new ->
// 2次的时间间隔小于2秒就退出了
if (new - old < 2000) {
finish()
} else {
drawerLayout?.snack("再按返回鍵退出")
}
}
// 从新写back方法
override fun onBackPressed() {
// 直接赋值就可以啦,是不是很简单呀
backPressedTime = System.currentTimeMillis()
}