kotlin之好用的Delegates实现双击back退出

kotlin之好用的Delegates实现双击back退出简介说 Delegates 之前 首先必须了解下 kotlin 的委托机制 这个委托机制还是很不错的 可以将一个对象的构造和设置值 都给委托给其它委托机制关键词 by 是不是很眼熟 这不是我们经常用过的 bylazy 没错懒加载就是用委托实现的自定义委托考大家一个问题 val 和 var 有啥区别吗 val 是不可变的变量 必须要在初始化化的时候赋值 var 是可变的变量 有没有考虑过为啥呢 其

简介

说Delegates之前,首先必须了解下kotlin的委托机制,这个委托机制还是很不错的,可以将一个对象的构造和设置值,都给委托给其它

委托机制

关键词by,是不是很眼熟,这不是我们经常用过的by lazy{} ,没错懒加载就是用委托实现的

自定义委托

考大家一个问题valvar有啥区别吗?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对象 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") } 
 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() } 
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/199338.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月26日 下午1:19
下一篇 2026年3月26日 下午1:20


相关推荐

  • 购买iPad Pro

    购买iPad Pro

    2026年3月15日
    2
  • 光棍节程序员闯关秀第9关(总共10关) 解题步骤

    光棍节程序员闯关秀第9关(总共10关) 解题步骤题目链接:http://segmentfault.com/game/?k=4999c12ce5be7c3cba227ba9f4f7d797解题步骤:1.应景嘛,把所有的空格替换成11112.8位二进制转换成一个byte,解释为ASCII字符3.得到一个BASE64加密在字符串4.用 BASE64Decoder解密5.另存为

    2022年7月16日
    19
  • Java 解析 XML[通俗易懂]

    Java 解析 XML[通俗易懂]Java解析XML标签:Java基础XML解析技术有两种DOMSAXDOM方式根据XML的层级结构在内存中分配一个树形结构,把XML的标签,属性和文本等元素都封装成树的节点对象优点:便于实现增删改查缺点:XML文件过大可能造成内存溢出SAX方式采用事件驱动模型边读边解析:从上到下一行行解析,解析到某一元素,调用相应解析方法优点:不会造成内存溢出,缺点:

    2022年6月4日
    37
  • WPF AvalonDock拖拽布局学习整理

    WPF AvalonDock拖拽布局学习整理AvalonDock提供了一个系统,允许开发人员使用类似于许多流行的集成开发环境(IDE)中的窗口对接系统来创建可自定义的布局。AvalonDock遵循MVVM设计。Model由Xceed.Wpf.AvalonDock.Layout命名空间中包含的类表示。此命名空间中的类是布局模型中的布局元素(例如LayoutAnchorable/LayoutDocument,LayoutAnchorab…

    2022年7月20日
    28
  • 养龙虾——-【openclaw 安装部署 】–linux安装部署指南

    养龙虾——-【openclaw 安装部署 】–linux安装部署指南

    2026年3月12日
    3
  • Arrays sort排序[通俗易懂]

    Arrays sort排序[通俗易懂]Arrays.sort默认是升序,如果我们需要降序排列数组?Arrays.sort(distances);——升序Arrays.sort(distances,Collections.reverseOrder());——降序再说说Collections集合类,用来排序集合的Collections.sort(list)——升序Collections.reverse(list…

    2022年10月20日
    9

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号