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的协成,发现使用协成能够帮助我们将异步代码转换成同步代码,能够极大的提高代码的可读性。

1.普通的异步写法

如下所示,为我们常见的一些异步代码,通常情况下,我们会传递一个callback到方法里面,等到异步代码执行完毕之后回调回来。

public fun realRequest(response: Callback) {
    Thread(Runnable {
        println("start request:" + address)
        Thread.sleep(1000)
        if (address.equals("failed")) {
            response.onError(0, "address failed")
        } else {
            response.onResult("success:" + address)
        }
    }).start()
}

我们调用这段代码如下

Request("test").realRequest(object: Callback {
    override fun onResult(result: String) {
        println("success!")
    }

    override fun onError(errorCode: Int, errorMsg: String) {
        println("errorcode:${errorCode},errorMsg:${errorMsg}")
    }

})

我们从这段代码里面可以看出,Request(“test”)前后的代码和回调方法里面的代码割裂开了,增加了阅读成本,另外如果回调方法特别长,阅读起来就会特别费劲。
那么我们可以尝试着用协成的方法来改写这段代码。

2.使用协成改写

我们可以在Request类里面增加一个suspend方法,将realRuest转变成同步方法,具体如下

class Request(val address:String) {

    //增加suspend方法
    public suspend fun request(): TestResult {
        return suspendCoroutine { continuation ->
            realRequest(object : Callback {
                override fun onResult(result: String) {
                    continuation.resume(TestResult(true,result))
                }

                override fun onError(errorCode: Int, errorMsg: String) {
                    continuation.resume(TestResult(false,errorMsg,errorCode))
                }
            })
        }
    }

    public fun realRequest(response: Callback) {
        Thread(Runnable {
            println("start request:" + address)
            Thread.sleep(1000)
            if (address.equals("failed")) {
                response.onError(0, "address failed")
            } else {
                response.onResult("success:" + address)
            }
        }).start()
    }
}

具体使用如下,在协成当中访问就可以了

GlobalScope.launch {
    val result = Request("test").request()
    println(result.toString())
}

在这里插入图片描述
如果我们引用的是一个库,不方便更改Request源码,那么也可以使用扩展的方式来实现,
如下所示,我们在Request外部给其增加了一个扩展方法outRequest

suspend fun Request.outRequest():TestResult{
    return suspendCoroutine { continuation ->
        this.realRequest(object :Callback{
            override fun onResult(result: String) {
                continuation.resume(TestResult(true,result))
            }

            override fun onError(errorCode: Int, errorMsg: String) {
                continuation.resume(TestResult(false,errorMsg,errorCode))
            }

        })
    }
}

使用方式也是完全一致

GlobalScope.launch {
    val result = Request("outTest").outRequest()
    println(result.toString())
}

在这里插入图片描述

3.多线程并发

如果我们想要发起多个请求,可以使用flow。

GlobalScope.launch {

    val start = System.currentTimeMillis()
    val r1 = Request("test1")
    val r2 = Request("test2")
    val r3 = Request("test3")
    val list = listOf(r1,r2,r3)

    flow {
        for (request in list) {
            val result = request.request()
            emit(result)
        }
    }.collect {
        println(it.toString())
    }
    val gap = System.currentTimeMillis() - start
    println("cost time:"+gap)
}

如上面代码所示,我们有三个异步请求,可以将其放到flow当中,分别进行emit,然后在collect当中获取结果。
每个异步任务执行时间是1秒,从结果当中可以发现,整体执行时间为3秒,可以看出所有的任务都是串行执行。
在这里插入图片描述
如果我们希望任务能够并发执行呢,可以使用channelFlow

GlobalScope.launch {

    val start = System.currentTimeMillis()
    val r1 = Request("test1")
    val r2 = Request("test2")
    val r3 = Request("test3")
    val list = listOf(r1,r2,r3)

    channelFlow {
        for (request in list){
            async {
                val result = request.request()
                send(result)
            }
        }
    }.collect {
        println(it.toString())
    }
    val gap = System.currentTimeMillis() - start
    println("cost time:"+gap)
}

从执行结果可以看出,任务为并发执行
在这里插入图片描述

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

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