IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Kotlin - 委托(by、Delegate)、懒加载 by lazy() -> 正文阅读

[移动开发]Kotlin - 委托(by、Delegate)、懒加载 by lazy()

类委托

把原本自己做的事情委托给另一个对象去做。装饰者模式和代理模式都通过委托复用了行为,Kotlin 在语言层面支持了委托。

interface Function {
    fun run(): String
    fun jump(): String
}

class Model1 : Function {
    override fun run(): String = "run"
    override fun jump(): String = "jump"
}
//装饰者模式
//重写时调用持有的实例去做
class Model2(val function: Function) : Function {    //持有一个实例
    override fun run() = function.run() + " fast"    //对实例加强
    override fun jump() = function.jump()            //委托实例做
}
//Kotlin委托
//实现Function接口需要的重写,委托给持有的实例去做
class Model3(val function: Function) : Function by function{
    //加强的功能还是需要自己重写
    //完全委托的功能可以不写,减少了模版代码
}

val model3 = Model3(Model1())
model3.run()

属性委托

by约定:将属性的 getter/setter 交给别的对象重写 getValue()/setValue() 去实现。也就是被 var 属性委托的对象的类要重写 getValue()、setValue()方法,被 val 属性委托的对象的类要重写 getValue() 方法。

//thisRef:属性所在类的类型
//property:属性
//value:属性的类型
operator fun getValue(thisRef: Any?, property: KProperty<*>)
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String)
class Phone {
    //一般是先委托再去被委托的类中重写,这样IDE能自动补全代码,手写也好去写类型
    val screen: String by ScreenFactory()    //val属性委托给屏幕对象
    var battery: String by BatteryFactory()  //var属性委托给电池对象
}

//被委托的屏幕类
class ScreenFactory {
    private val str: String = "屏幕"
    operator fun getValue(phone: Phone, property: KProperty<*>): String = str
}

//被委托的电池类
class BatteryFactory {
    private var str = "电池"
    operator fun getValue(phone: Phone, property: KProperty<*>): String = str
    operator fun setValue(phone: Phone, property: KProperty<*>, s: String) { str = s }
}

val phone = Phone()
println(phone.battery)    //打印:电池
phone.battery = "坏电池"
println(phone.battery)    //打印:坏电池

使用场景:?

//被委托的类
class Find {
    operator fun getValue(activity: Activity, kProperty: KProperty<*>): T {
        println("操作的属性名是 ${property.name}")
        return activity.findViewById(id)
    }
}
//给Activity扩展
fun <T : View> Activity.find(id: Int) = Find<T>(id)
//使用
class KotlinActivity : AppCompatActivity() {
    private val image: ImageView by find(R.id.iv)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
}

系统提供的一些委托 Delegate

Delegates.notNull( ):可以不在创建实例的时候初始化,而是在延迟到之后再初始化。属性委托后,编译器不会再做非空检查,不初始化也不会报错,所以需要做到自己可控(无论在类中还是类外要对属性赋值),否则在使用之前未初始化,调用会报错?IllegalStateException。

Delegates.notNull()

适用于:基本类型、引用类型。

不支持外部注入工具将它直接注入到Java字段中。

lateinit适用于:引用类型。
class Demo {
    var num: Int by Delegates.notNull()
}

val demo = Demo()
demo.num = 3
println(demo.num)

Delegates.observable( ):类似于观察者用于监听属性值发生变更,当属性值被更改后会往外抛出一个回调。

class Demo {
    //initialValue参数:初始化值
    //onChange参数:是一个Lambda回调提供三个参数可用:property属性,oldValue旧值,newValue新值
    var num: Int by Delegates.observable(1) { property, oldValue, newValue -> println("发生了变化:${property.name},$oldValue,$newValue") }
}

val demo = Demo()
demo.num = 3    //打印:发生了变化:num,1,3

Delegates.vetoable( ):同上,不同的是回调会返回一个 Boolean 值,来决定此次修改是否通过。

class Demo {
    //新值是负数才能修改成功
    var num: Int by Delegates.vetoable(1) { property, oldValue, newValue -> newValue < 0 }
}

val demo = Demo()
demo.num = 3
println(demo.num)   //打印:1
demo.num = -3
println(demo.num)   //打印:3

幕后属性 Backing Property

关联知识点:幕后字段 Backing Field、延迟初始化 lateinit

? ? ? ? 类似于 Java 私有化字段并提供公共访问的写法(封装),Kotlin 一般不这样写,毕竟在 getter/setter中就能对字段的操作加以限制,是用来实现懒加载的惯用技术。

????????如果一个类有两个概念上相同的属性,一个是公共 API 的一部分,另一个是实现细节,那么使用下划线作为私有属性名称的前缀。

????????幕后属性 _bitmap 是私有的,它用来存储一组 Bitmap,而另一个同样类型的 bitmap 用来提供一组 Bitmap 的访问。这样只有当第一次访问 BitmapManager.bitmaps 时,才会去加载 Bitmap。第二次访问时,也不会重新加载 Bitmap,可直接返回 _bitmap。

????????下面这段代码就是 Kotlin 提供的?lazy()?内部运用的技术。

class BitmapManager {
    //幕后属性用于私有化 Bitmap
    private var _bitmaps: List<Bitmap>? = null
    //提供外部访问 Bitmap
    val bitmaps: List<Bitmap>
        get() {
            if (_bitmaps == null) {
                _bitmaps = loadBitmaps()
            }
            return _bitmaps!!
        }
}

懒加载 by lazy()

  • 延迟对象的初始化,直到第一次访问(使用)它。当初始化消耗大量资源时使用。
  • 只能对 val 的属性使用。第一次调用 getter 执行传递的 Lambda 并记录结果,再次调用只返回之前的结果。
  • 线程安全。
Lazy.ktLazy 接口public interface Lazy<out T> {
? ? public val value: T? ? ? ? //懒加载的值,一旦被赋值件将不会被改变
? ? public fun isInitialized(): Boolean? ? ? ? //检查是否被初始化
}
by 关键字

public inline operator fun <T> Lazy<T>.getValue(thisRef: Any?, property: KProperty<*>): T = value

by的实现就是把属性的getter和被委托对象的类中重写的getValue()配对,这里是Lazy的扩展函数形式。
LazyJVM.ktlazy() 函数

public actual fun <T> lazy(initializer: () -> T): Lazy<T> = SynchronizedLazyImpl(initializer)

lazy()参数接收一个Lambda返回一个Lazy的实现类实例,有很多重载一般使用上面这个线程同步的,原理双重校验锁。

使用场景:所有的员工只有柜台是女性,针对少数使用到的情况选择懒加载。

//这样写在实例初始化的时候就会初始化 gender 这个属性。
class Staff(val name: String, var position: String) {
    val gender: String = if (position == "Counter") "female" else "male"
}
//修改之后没有了= 赋值,只有在初次访问sex这个属性的时候,才会进行初始化。
class Staff(val name: String, var position: String) {
    val gender: String by lazy {
        if (position == "Counter") "female" else "male"
    }
}
  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-05-27 17:21:57  更:2022-05-27 17:22:04 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 1:03:18-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码