iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >Android开发之Kotlin委托的原理与使用方法是什么
  • 646
分享到

Android开发之Kotlin委托的原理与使用方法是什么

2023-07-05 15:07:04 646人浏览 八月长安
摘要

今天小编给大家分享一下Android开发之Kotlin委托的原理与使用方法是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧

今天小编给大家分享一下Android开发Kotlin委托的原理与使用方法是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

前言

设计模式中,委托模式(Delegate Pattern)与代理模式都是我们常用的设计模式(Proxy Pattern),两者非常的相似,又有细小的区分。

委托模式中,委托对象和被委托对象都是同一类型的对象,委托对象将任务委托给被委托对象来完成。委托模式可以用于实现事件监听器、回调函数等功能。

代理模式中,代理对象与被代理对象是两种不同的对象,代理对象代表被代理对象的功能,代理对象可以控制客户对被代理对象的访问。代理模式可以用于实现远程代理、虚拟代理、安全代理等功能。

以类的委托与代理来举例,委托对象和被委托对象都实现了同一个接口或继承了同一个类,委托对象将任务委托给被委托对象来完成。代理模式中,代理对象与被代理对象实现了同一个接口或继承了同一个类,代理对象代表被代理对象,客户端通过代理对象来访问被代理对象。

两者的区别:

他们虽然都有同一个接口,主要区别在于委托模式中委托对象和被委托对象是同一类型的对象,而代理模式中代理对象与被代理对象是两种不同的对象。总的来说,委托模式是为了将方法的实现交给其他类去完成,而代理模式则是为了控制对象的访问,并在访问前后进行额外的操作。

而我们常用的委托模式怎么使用?在 Java 语言中需要我们手动的实现,而在 Kotlin 语言中直接通过关键字 by 就可以实现委托,其实现更加优雅、简洁了。

我们在开发一个 Android 应用中,常用到的委托分为:

  • 接口/类的委托

  • 属性的委托

  • 结合lazy的延迟委托

  • 观察者的委托

  • Map数据的委托

一、接口/类委托

我们可以选择使用接口来实现类似的效果,也可以直接传参,当然接口的方式更加的灵活,比如我们这里就以接口比如我定义一个攻击与防御的行为接口:

interface IUserAction {    fun attack()    fun defense()}

定义了用户的行为,有攻击和防御两种操作!接下来我们就定义一个默认的实现类:

class UserActionImpl : IUserAction {    override fun attack() {        YYLogUtils.w("默认操作-开始执行攻击")    }    override fun defense() {        YYLogUtils.w("默认操作-开始执行防御")    }}

都是很简单的代码,我们定义一些默认的操作,如果任意类想拥有攻击和防御的能力就直接实现这个接口,如果想自定义攻击和防御则重写对应的方法即可。

如果使用 Java 的方式实现委托,大致代码如下:

class UserDelegate1(private val action: IUserAction) : IUserAction {    override fun attack() {        YYLogUtils.w("UserDelegate1-需要自己实现攻击")    }    override fun defense() {        YYLogUtils.w("UserDelegate1-需要自己实现防御")    }}

如果使用 Kotlin 的方式实现则是:

class UserDelegate2(private val action: IUserAction) : IUserAction by action

如果 Kotlin 的实现不想默认的实现也可以重写部分的操作:

class UserDelegate3(private val action: IUserAction) : IUserAction by action {    override fun attack() {        YYLogUtils.w("UserDelegate3 - 只重写了攻击")    }}

那么使用起来就是这样的:

    val actionImpl = UserActionImpl()    UserDelegate1(actionImpl).run {        attack()        defense()    }    UserDelegate2(actionImpl).run {        attack()        defense()    }    UserDelegate3(actionImpl).run {        attack()        defense()    }

打印日志如下:

Android开发之Kotlin委托的原理与使用方法是什么

其实在 Android 源码中也有不少委托的使用,例如生命周期的 Lifecycle 委托:

Lifecycle 通过委托机制实现其功能。具体来说,组件可以将自己的生命周期状态委托给 LifecycleOwner 对象,LifecycleOwner 对象则负责管理这些组件的生命周期。

例如,在一个 Activity 中,我们可以通过将 Activity 对象作为 LifecycleOwner 对象,并将该对象传递给需要注册生命周期的组件,从而实现组件的生命周期管理。 页面可以使用 getLifecycle() 方法来获取它所依赖的 LifecycleOwner 对象的 Lifecycle 实例,并在需要时将自身的生命周期状态委托给该 Lifecycle 实例。

通过这种委托机制,Lifecycle 实现了一种方便的方式来管理组件的生命周期,避免了手动管理生命周期带来的麻烦和错误。

class AnimUtil private constructor() : DefaultLifecycleObserver {      ...    private fun addLoopLifecycleObserver() {        mOwner?.lifecycle?.addObserver(this)    }    // 退出页面的时候释放资源    override fun onDestroy(owner: LifecycleOwner) {        mAnim?.cancel()        destory()    }}

除此之外委托还特别适用于一些可配置的功能,比如 Resutl-api 的封装,如果当前页面需要开启 startActivityForResult 的功能,就实现这个接口,不需要这个功能就不实现接口,达到可配置的效果。

interface ISAFLauncher {    fun <T : ActivityResultCaller> T.initLauncher()    fun getLauncher(): GetSAFLauncher?}

由于代码是固定的实现,目标Activity也不需要重新实现,我们只需要实现默认的实现即可:

class SAFLauncher : ISAFLauncher {    private var safLauncher: GetSAFLauncher? = null    override fun <T : ActivityResultCaller> T.initLauncher() {        safLauncher = GetSAFLauncher(this)    }    override fun getLauncher(): GetSAFLauncher? = safLauncher}

使用起来我们直接用默认的实现即可:

class DemoActivity : BaseActivity, ISAFLauncher by SAFLauncher() {    override fun init() {        initLauncher()  // 实现了接口还需要初始化Launcher    }    fun GotoOtherPage() {        //使用 Result Launcher 的方式启动,并获取到返回值        getLauncher()?.launch<DemoCircleActivity> { result ->            val result = result.data?.getStringExtra("text")            toast("收到返回的数据:$result")        }    }}

这样是不是就非常简单了呢?具体如何使用封装 Result Launcher 可以看看我去年的文章 【传送门】

二、属性委托

除了类与接口对象的委托,我们还常用于属性的委托。

我知道了!这么弄就行了。

private val textStr by "123"

哎?怎么报错了?其实不是这么用的。

属性委托和类委托一样,属性的委托其实是对属性的 set/get 方法的委托。

需要我们把 set/get 方法委托给 setValue/getValue 方法,因此被委托类(真实类)需要提供 setValue/getValue 方法,val属性只需要提供 getValue 方法。

我们修改代码如下:

    private val textStr by TextDelegate()    class TextDelegate {        operator fun getValue(thisRef: Any?, property: KProperty<*>): String {            return "我是赋值给与的文本"        }    }

打印的结果:

Android开发之Kotlin委托的原理与使用方法是什么

而我们定义一个可读写的属性则可以

  private var textStr by TextDelegate()    class TextDelegate {        operator fun getValue(thisRef: Any?, property: KProperty<*>): String {            return "我是赋值给与的文本"        }        operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {            YYLogUtils.w("设置的值为:$value")        }    }    YYLogUtils.w("textStr:$textStr")    textStr = "abc123"

打印则如下:

Android开发之Kotlin委托的原理与使用方法是什么

为了怕大家写错,我们其实可以用接口来限制,只读的和读写的属性,我们分别可以用 ReadOnlyProperty 与 ReadWriteProperty 来限制:

class TextDelegate : ReadOnlyProperty<Any, String> {        override fun getValue(thisRef: Any, property: KProperty<*>): String {            return "我是赋值给与的文本"        }    }    class TextDelegate : ReadWriteProperty<Any, String> {        override fun getValue(thisRef: Any, property: KProperty<*>): String {            return "我是赋值给与的文本"        }        override fun setValue(thisRef: Any, property: KProperty<*>, value: String) {            YYLogUtils.w("设置的值为:$value")        }    }

那么实现的方式和上面自己实现的效果是一样的。如果要使用属性委托可以选用这种接口限制的方式实现。

我们的属性除了委托给类去实现,同时也能委托给其他属性(Kotlin 1.4+)来实现,例如:

    private var textStr by TextDelegate2()    private var textStr2 by this::textStr

其实是内部委托了对象的 get 和 set 函数。相对委托对象而言性能更好一些。而委托对象去实现,不仅增加了一个委托类,而且还还在初始化时就创建了委托类的实例对象,算起来其实性能并不好。

所以属性的委托不要滥用,如果要用,可以选择委托现成的其他属性来完成,或者使用延迟委托Lazy实现,或者使用更简单的方式实现:

    private val industryName: String        get() {            return "abc123"        }

对于只读的属性,这种方式也是我们常见的使用方式。

三、延迟委托

如果说使用类来实现委托不那么好的话,其实我们可以使用延迟委托。延迟关键字 lazy 接收一个 lambda 表达式,最后一行代表返回值给被推脱的属性。

默认的 Lazy 实现:

    val name: String by lazy {        YYLogUtils.w("第一次调用初始化")        "abc123"    }    YYLogUtils.w(name)    YYLogUtils.w(name)    YYLogUtils.w(name)

只有在第一次使用此属性的时候才会初始化,一旦初始化之后就可以直接获取到值。

日志打印:

Android开发之Kotlin委托的原理与使用方法是什么

它的内部其实也是使用的是类的委托实现。

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

最终的实现是由 SynchronizedLazyImpl 类生成并实现的:

private class SynchronizedLazyImpl<out T>(initializer: () -> T, lock: Any? = null) : Lazy<T>, Serializable {    private var initializer: (() -> T)? = initializer    @Volatile private var _value: Any? = UNINITIALIZED_VALUE    // final field is required to enable safe publication of constructed instance    private val lock = lock ?: this    override val value: T        get() {            val _v1 = _value            if (_v1 !== UNINITIALIZED_VALUE) {                @Suppress("UNCHECKED_CAST")                return _v1 as T            }            return synchronized(lock) {                val _v2 = _value                if (_v2 !== UNINITIALIZED_VALUE) {                    @Suppress("UNCHECKED_CAST") (_v2 as T)                } else {                    val typedValue = initializer!!()                    _value = typedValue                    initializer = null                    typedValue                }            }        }    override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE    override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."    private fun writeReplace(): Any = InitializedLazyImpl(value)}

我们可以直接看 value 的 get 方法,如果_v1 !== UNINITIALIZED_VALUE 则表明已经初始化过了,就直接返回 value ,否则表明没有初始化过,调用initializer方法,也就是 lazy 的 lambda 表达式返回属性的赋值。

跟我们自己实现类的委托类似,也是实现了getValue方法。只是多了判断是否初始化的一些相关逻辑。

lazy的参数分为三种类型:

  • SYNCHRONIZED:添加同步,使lazy延迟初始化线程安全

  • PUBLICATION:初始化的lambda表达式,可以在同一时间多次调用,但是只有第一次的返回值作为初始化值

  • NONE:没有同步锁,非线程安全

默认情况下,对于 lazy 属性的求值是同步锁的(synchronized),是可以保证线程安全的,但是如果不需要线程安全和减少性能花销可以可以使用 lazy(LazyThreadSafetyMode.NONE){} 即可。

四、观察者委托

除了对属性的值进行委托,我们甚至还能对观察到这个变化过程:

使用 observable 委托监听值的变化:

    var values: String by Delegates.observable("默认值") { property, oldValue, newValue ->        YYLogUtils.w("打印值: $oldValue -> $newValue ")    }    values = "第一次修改"    values = "第二次修改"    values = "第三次修改"

打印:

Android开发之Kotlin委托的原理与使用方法是什么

我们还能使用 vetoable 委托,和 observable 一样可以观察属性的变化,不同的是 vetoable 可以决定是否使用新值。

    var age: Int by Delegates.vetoable(18) { property, oldValue, newValue ->        newValue > oldValue    }    YYLogUtils.w("age:$age")    age = 14    YYLogUtils.w("age:$age")    age = 20    YYLogUtils.w("age:$age")    age = 22    YYLogUtils.w("age:$age")    age = 20    YYLogUtils.w("age:$age")

我们需要返回 booble 值觉得是否使用新值,比如上述的例子就是当新值大于老值的时候才赋值。那么打印的日志就是如下:

Android开发之Kotlin委托的原理与使用方法是什么

虽然这种方式我们并不常用,一般我们都是使用类似 Flow 之类的工具在源头就处理了逻辑,使用这种方式我们就可以在属性的赋值过程中进行拦截了。在一些特定的场景下还是有用的。

五、Map委托

我们的属性不止可以使用类的委托,延迟的委托,观察的委托,还能委托Map来进行赋值。

当属性的值与 Map 中 key 相同的时候,我们可以把对应 key 的 value 取出来并赋值给属性:

class Member(private val map: Map<String, Any>) {    val name: String by map    val age: Int by map    val dob: Long by map    override fun toString(): String {        return "Member(name='$name', age=$age, dob=$dob)"    }}

使用:

        val member = Member(mapOf("name" to "guanyu", "age" to 36, Pair("dob", 1234567890L)))        YYLogUtils.w("member:$member")

打印的日志:

Android开发之Kotlin委托的原理与使用方法是什么

但是需要注意的是,map 中的 key 名字必须要和属性的名字一致才行,否则委托后运行解析时会抛出 NoSuchElementException 异常提示。

例如我们在 Member 对象中加入一个并不存在的 address 属性,再次运行就会报错。

Android开发之Kotlin委托的原理与使用方法是什么

而我们把 Int 的 age 属性赋值给为字符串也会报类型转换异常:

Android开发之Kotlin委托的原理与使用方法是什么

所以一定要一一对应才行哦,我怎么感觉有一点 typescript 结构赋值的那味道 - - !

Android开发之Kotlin委托的原理与使用方法是什么

以上就是“Android开发之Kotlin委托的原理与使用方法是什么”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注编程网精选频道。

--结束END--

本文标题: Android开发之Kotlin委托的原理与使用方法是什么

本文链接: https://www.lsjlt.com/news/352928.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Android开发之Kotlin委托的原理与使用方法是什么
    今天小编给大家分享一下Android开发之Kotlin委托的原理与使用方法是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧...
    99+
    2023-07-05
  • Android开发之Kotlin委托的原理与使用详解
    目录前言一、接口/类委托二、属性委托三、延迟委托四、观察者委托五、Map委托总结前言 在设计模式中,委托模式(Delegate Pattern)与代理模式都是我们常用的设计模式(Pr...
    99+
    2023-03-23
    Kotlin委托原理 Kotlin委托使用 Android Kotlin委托 Kotlin委托
  • C#委托的使用方法是什么
    在C#中,委托是一种类型,用于引用一个或多个方法。委托可以看作是函数指针,它可以被用来调用方法。 使用委托的步骤如下: 定义委托:...
    99+
    2024-03-06
    C#
  • C#中委托的概念与使用方法是什么
    本篇内容主要讲解“C#中委托的概念与使用方法是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C#中委托的概念与使用方法是什么”吧!委托的概念委托这个名字取的神乎其神的,但实质是函数式编程,把...
    99+
    2023-07-05
  • Android广播机制原理与开发的方法是什么
    今天小编给大家分享一下Android广播机制原理与开发的方法是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。广播机制简介...
    99+
    2023-07-05
  • android组件化开发的原理是什么
    Android组件化开发的原理是将一个大型的应用程序拆分成多个独立的组件,每个组件包含自己的功能模块和界面,然后通过定义清晰的接口和...
    99+
    2023-10-22
    android
  • Android handle-message的发送与处理方法是什么
    在Android中,`Handler`类用于发送和处理消息。发送消息:1. 创建一个`Handler`对象。2. 创建一个`Mess...
    99+
    2023-08-11
    Android
  • android事件分发与处理的方法是什么
    Android事件分发与处理的方法主要有以下几种:1. 触摸事件分发处理:Android中的触摸事件主要包括按下、移动、抬起等动作。...
    99+
    2023-09-13
    android
  • android控件开发的方法是什么
    Android控件开发的方法主要有以下几种:1. 基于XML布局文件进行控件的开发:可以使用XML布局文件来定义控件的外观和布局,然...
    99+
    2023-09-14
    android
  • Android开发使用strings.xml多语言翻译的方法是什么
    这篇“Android开发使用strings.xml多语言翻译的方法是什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“And...
    99+
    2023-07-02
  • android组件化开发的方法是什么
    Android组件化开发的方法有以下几种:1. 模块化开发:将整个项目拆分为多个独立的模块,每个模块独立开发、编译和运行。每个模块可...
    99+
    2023-10-10
    android
  • Android开发导出apk的方法是什么
    Android开发导出apk的方法有两种:1. 使用Android Studio:在Android Studio中,选择菜单中的“B...
    99+
    2023-10-12
    Android
  • android蓝牙简单开发的方法是什么
    本篇内容介绍了“android蓝牙简单开发的方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!概述前段时间学习了一些蓝牙开发的知识,记...
    99+
    2023-06-21
  • android人脸识别开发的方法是什么
    在Android上进行人脸识别开发有以下几种方法:1. 使用OpenCV库:OpenCV是一个开源的计算机视觉库,可以用于人脸检测和...
    99+
    2023-10-09
    android
  • Android开发文件存储的方法是什么
    这篇文章主要介绍“Android开发文件存储的方法是什么”,在日常操作中,相信很多人在Android开发文件存储的方法是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Android开发文件存储的方法是什么...
    99+
    2023-06-25
  • android文件加密开发的方法是什么
    Android文件加密开发的方法可以有多种,以下是其中几种常见的方法:1. 使用Android提供的加密API:Android提供了...
    99+
    2023-10-18
    android
  • Scala+Eclipse+Android手机开发的方法是什么
    本篇内容介绍了“Scala+Eclipse+Android手机开发的方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!众所周知Andr...
    99+
    2023-06-17
  • Java程序的开发与运行原理是什么
    这篇文章主要介绍“Java程序的开发与运行原理是什么”,在日常操作中,相信很多人在Java程序的开发与运行原理是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java程序的开发与运行原理是什么”的疑惑有所...
    99+
    2023-06-16
  • Web开发之canvas2image的用法是什么
    canvas2image是一个javascript库,用于将HTML5 canvas元素转换为图像。它的用法如下:1. 引入canv...
    99+
    2023-10-20
    Web开发
  • Java服务器端开发人员不采用Kotlin的原因是什么
    这篇文章主要讲解了“Java服务器端开发人员不采用Kotlin的原因是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java服务器端开发人员不采用Kotlin的原因是什么”吧!自使用Ja...
    99+
    2023-06-15
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作