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 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> 谈谈Java/Kotlin中接口回调 -> 正文阅读

[移动开发]谈谈Java/Kotlin中接口回调

在谈接口回调之前,想什么是接口?在学习类的时候,我们就得知接口主要是用来把某个功能抽象起来,之后,不同的类实现此功能,但其实现的功能不同。

一个生动的例子,把动物的叫这一行为抽象为一个接口,之后不同动物由不同的类代替,这些动物类都实现了这个“叫”接口,但是,他们实现不一样,因为每个动物的叫声都不一样

上面所述为接口的基本定义和功能,接口除了上面的功能外,还可以用来回传数据,也就是所谓的接口回调,即本文谈论的主题

接口回调应用情形

接口回调主要是将数据/状态回传给调用者,举个常见的例子,下载功能

我们定义一个下载的类,此类存在一个download方法,我们只要实例化此类,用对象的调用方式来调用download方法,即可开始下载

问题来了,我们想要得到下载完成这个状态,那么该如何实现呢?

大家可能想到的是一种较为简单的方法,使用返回值来判断当前是否完成,给download方法声明返回值,下载完毕之后返回true

上面的方法可行是可行,但是如果需要得到多个数据呢?如下载完成之后需要返回一个File对象,下载失败则是返回错误信息Exception,按照上面的逻辑的话,你得定义两个类,用来存储数据?然后根据不同的情况返回不同的对象?但是返回值的对象只能是一种类型,你两个类该怎么办?

于是呢,我们可以选择接口回调,可以比较方便的实现上述的问题。

class DownloadUtil {
    fun download(downloadListener: DownloadListener) {
        try {
            //下载操作...
            //一般下载操作肯定是有个File对象进行读写操作,这里我就省略了
            downloadListener.success(file)
        } catch (e: IOException) {
            downloadListener.error(e)
        }
    }

    interface DownloadListener {
        fun success(file: File)
        fun error(e: Exception)
    }
}

可以看到,DownloadListener有两个接口方法,success()error(),当调用者调用的时候,传递了一个接口对象,之后在各自不同的方法就可以处理不同两种情况的逻辑了

val downloadUtil = DownloadUtil()
downloadUtil.download(object :DownloadUtil.DownloadListener{
    override fun success(file: File) {
        //下载成功的相关操作
    }

    override fun error(e: Exception) {
        //下载失败的相关操作
    }

})

Kotlin优雅的接口回调

Kotlin与Java不同的是,如果某个接口有一个方法的话,可以使用Kotlin中的接口参数
这里就谈谈如何使用Kotlin优雅的实现一个接口多方法

上面下载的接口我们是定义了两个方法,一个是下载成功,另外是下载失败,在实现接口的时候,我们必须两个方法都实现,哪怕你不关心某个方法,你都要实现,但方法里面不写任何代码,如果接口方法多的话,简直是地狱

Kotlin的object关键字就是相当于Java中用new来实现接口方法

那么有没有可以自由选择实现某个接口方法的办法呢?当然有,那就是Kotlin中提供的DSL语法

我们把上面的用Kotlin优雅的重构一遍

1.接口构造类

我们需要把接口改造成接口的构造类,如下代码所示

inner class ListenerBuilder {
    internal var successListener: ((file: File) -> Unit)? = null
    internal var errorListener: ((e: Exception) -> Unit)? = null

    //这里的方法名之后需要调用
    fun onSuccess(action: (file: File) -> Unit) {
        successListener = action
    }

    fun onError(action: (e: Exception) -> Unit) {
        errorListener = action
    }
}

对比:
interface DownloadListener {
    fun success(file: File)
    fun error(e: Exception)
}

fun success(file: File)?改造为接口参数((file: File) -> Unit),如果有返回值,把Unit改成对应返回值类型即可

2.提供方法传递接口构造类

private lateinit var mListener: ListenerBuilder

fun download(listener: ListenerBuilder.() -> Unit) {
    mListener = ListenerBuilder().also(listener)
    try {
        //下载操作...
        if (::mListener.isInitialized) {
            mListener.successListener?.invoke(File(""))
        }
    } catch (e: IOException) {
        if (::mListener.isInitialized) {
            mListener.errorListener?.invoke(e)
        }
    }
}

PS:这里你也可以选择声明另外的方法用于单独设置接口,之后调用逻辑就可以不需要传递接口参数过来,这个看你喜欢吧

3.调用

val downloadUtil = DownloadUtil()
    downloadUtil.download{
        //这里onSuccess和onError可选,IDE不会报错
        onSuccess { 

        }
        onError { 

        }
    }

下载类源码

class DownloadUtil {
    private lateinit var mListener: ListenerBuilder

    fun registerListener(listener: ListenerBuilder.() -> Unit) {
        mListener = ListenerBuilder().also(listener)
    }
    fun download(listener: ListenerBuilder.() -> Unit) {
        mListener = ListenerBuilder().also(listener)
        try {
            //下载操作...
            if (::mListener.isInitialized) {
                mListener.successListener?.invoke(File(""))
            }
        } catch (e: IOException) {
            if (::mListener.isInitialized) {
                mListener.errorListener?.invoke(e)
            }
        }
    }

    inner class ListenerBuilder {
        internal var successListener: ((file: File) -> Unit)? = null
        internal var errorListener: ((e: Exception) -> Unit)? = null

        //这里的方法名之后需要调用
        fun onSuccess(action: (file: File) -> Unit) {
            successListener = action
        }

        fun onError(action: (e: Exception) -> Unit) {
            errorListener = action
        }
    }

}
  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-09-13 11:27:25  更:2022-09-13 11:27:40 
 
开发: 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 4:38:56-

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