Kotlin协程-从一到多

这篇具有很好参考价值的文章主要介绍了Kotlin协程-从一到多。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

上一篇文章,我介绍了Kotlin协程的创建,使用,协作等内容。本篇将引入更多的使用场景,继续带你走进协程世界。

使用协程处理异步数据流

常用编程语言都会内置对同一类型不同对象的数据集表示,我们通常称之为容器类。不同的容器类适用于不同的使用场景。Kotlin的Flow就是在异步计算的需求下引入的,用于表示异步的数据流。

Flow

“问渠哪得清如许,为有源头活水来”,异步数据流的基本就是以某种方式获得异步数据。Kotlin提供了多种种方式,比较常用的就是Kotlin协程包的asFlow扩展和flow构造器。前者是对普通数据集的Flow化封装,没有更多可言,我们着重来看后者。
flow构造器的主要目标就是产生一个异步数据流,它是一个泛型函数,参数是一个挂起函数,并且是FlowCollector是扩展函数。这个接口只有一个emit方法,就是为创建的Flow提供异步计算的数据的,因为它是挂起函数,所以我们能在里面使用其他挂起函数计算异步值,然后通过emit方法将值发送出去,如此反复就能为下游操作提供源源不断的数据流了。
事情还没完,上面的步骤我们只是规定了创建数据的方式,并没有真正执行,也就是建好了道路,但是还没有车上路。那么,怎样才能让车在路上跑呢,查看Flow的接口会发现,它提供了collect方法来处理数据。collect接收一个挂起函数作为处理逻辑,但是同时,collect方法本身也是挂起函数,所以,这个方法只能在挂起函数中运行。有了这些知识,我们就可以写出最简单的异步数据流了。

 1uspend fun compute():Int{
             delay(123)
             return 1024
 }
 
 viewModelScope.launch {
     val flow=flow<Int> {
         emit(9527)
         emit(compute())
        delay(256)
        emit(256)
    }
    flow.collect {
        println(it)
    }
}

flow构造器里面随意做各种操作,只要在必要的时候传递结果就行了,但是需要注意的是,emit方法只能运行在同一个协程里。乍一看,这样分开写和写在一起并没有本质上的差别,但Flow还能做到更多。

该给Flow换个工作环境了

上一节,我们那个简单的示例,假如把构造器里面的数据获取方法换成网络请求,应用就歇菜了。因为它们都是运行在主线程里面的。那么这个时候,看过上一篇文章的小伙伴马上就会反应过来,用withContext方法在构造器里面切换线程就行了哇。思路是很对,因为Flow的默认配置就是构造器和collect方法工作在同一线程,既然现在主线程不让运行,那就把构造器的线程切换一下就行了呗。然后事实并不是这样,这样写出来的代码根本无法运行。因为官方提供了唯一的flowOn方法来切换构造器的执行线程。使用也很简单,就是对创建好的Flow对象配置一次flowOn方法就行了。

val flow=["1.jpg","2.jpg"].asFlow()
flow.map { decode(it) }
        .flowOn(Dispatchers.IO)
viewModelScope.launch {
    flow.collect{
        adapter.add(it)
    }

有些中间处理逻辑

熟悉RxJava的小伙伴可能有疑问了,这些操作RxJava也能完成,甚至还有更多的操作符来支持中间状态的处理,那么异步数据流能做到这些吗。毫无疑问,它可以。普通的数据集有map,filter等操作方法,对于异步数据流来说,这些方法同样适用。而且这些方法参数都是挂起函数,都可以执行异步操作。而且它还有个更灵活的transform方法,这个方法可以定制自己的操作符,实现更灵活的数据操作。

当然,上面那些操作符都只能实现单一异步流的操作,对于多数据流的支持,它也同样不在话下。zip可以将两个两个数据源两两合并起来,合成的数据流长度为两个数据流中最短的那个数据流的长度。combine则与zip不同,它会将两个数据流最近的发送数据作为输入,也就是说,假如一块一慢的两个数据源,慢的数据源的元素可能会被多次取到,从而最终的数据流比最短的那个都长。

val flow = flowOf(1, 2).delayEach(10)
val flow2 = flowOf("a", "b", "c").delayEach(15)
flow.combine(flow2) { i, s -> i.toString() + s }.collect {
     println(it) // Will print "1a 2a 2b 2c"
}

结束状态跟踪

上一节提到,由于数据源和处理逻辑不在同一个地方,所以很难确定最终的数据流大小,进而不知道数据流什么时候处理结束。而且中间操作也可能会改变数据流的大小,由此就更加难以确定数据处理结束的时机了。但是我们有的时候却需要在数据处理完成后做一些操作,该怎么办呢?这个时候当然是该onCompletion方法上场了。这个方法有一个可为空的Throwable类型参数,很显然,这可以同时指示两种处理结果,成功或者失败,失败就会将异常对象传递进来。

多个协程共同工作

很多时候,避免不了让多个协程共同工作。对于返回单个值的协程,上一篇我们也提到过了,可以传递async构造器的返回对象Deferred,但是局限性就是这个对象只能传递一个值。针对多值传递的情况,Kotlin提供了Channel的解决方法。Channel类似于阻塞队列,数据通过send方法发送出去,在另外的地方使用receive方法接收。通过这种方法,我们可以极大提供协程的工作效率。利用它就可以轻松实现生产者和消费者模型。

 val chanel=Channel<Int>()
 viewModelScope.launch(Dispatchers.IO) {
     for (i in 1..5){
         delay(1000)
         chanel.send(i)
     }
 }
 viewModelScope.launch { 
     for (i in chanel){
        println("Handle ${i}")
    }
}

当然,这只是最简单的用法,还可以加入更多的生产者,或者不再需要数据时取消,甚至还有专门的product构造器,直接获得返回多个值的协程对象。

总结

Kotlin协程有很多有用的API,这些API覆盖了大部分异步使用的场景。所以在使用协程的时候,我们首先需要明确使用场景,再根据使用场景确定使用哪一套API,这可以使我们避免陷入API恐惧症。为此,我根据这两篇文章的内容,整理出了一份情景表格,实际开发中可以参照使用。
Kotlin协程构造器

API 使用场景
launch 执行耗时操作,不需要返回值
async 需要获取耗时操作的单个返回值
produce 需要获取耗时操作的多个返回值

Kotlin协程协同工具

API 使用场景
Flow 操作异步数据流
Channel 协程间通信

青山不改,绿水长流,咱们下期见!文章来源地址https://www.toymoban.com/news/detail-486639.html

到了这里,关于Kotlin协程-从一到多的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Kotlin 协程一 —— 协程 Coroutine

    1.1.1基本定义 进程 进程是一个具有一定独立功能的程序在一个数据集上的一次动态执行的过程,是操作系统进行资源分配和调度的一个独立单位,是应用程序运行的载体。 进程是资源分配的最小单位,在单核CPU中,同一时刻只有一个程序在内存中被CPU调用运行。 线程 基本的

    2024年02月05日
    浏览(49)
  • kotlin语法进阶 - 协程(一)协程基础

    协程并不是一个新的概念,而是一个非常老的概念,很多语言都支持协程,建议去浏览器去了解一下协程的历史和基本概念,这里我们只讲一下kotlin中的协程的作用。 从代码实现角度来看:kotlin协程底层是用线程实现的,是一个封装完善供开发者使用的线程框架。kotlin的一个

    2024年02月09日
    浏览(45)
  • Kotlin协程学习之-02

    协程的基本使用 GlobalScope.launch 生命周期与进程一致,且无法取消 runBlocking 会阻塞线程,一般在测试阶段可以使用 val coroutineScope = CoroutineScope(context) coroutineScope.launch 通过context参数去管理和控制协程的生命周期 用法 val coroutineScope = CoroutineScope(context) coroutineScope.launch(Dispatche

    2024年01月22日
    浏览(44)
  • Kotlin 协程 - 多路复用 select()

            又叫选择表达式,是一个挂起函数,可以同时等待多个挂起结果,只取用最快恢复的那个值(即多种方式获取数据,哪个更快返回结果就用哪个)。         同时到达 select() 会优先选择先写子表达式,想随机(公平)的话使用 selectUnbiased() 替换 。         能

    2024年02月10日
    浏览(45)
  • Kotlin协程-从理论到实战

    上一篇文章从理论上对Kotlin协程进行了部分说明,本文将在上一篇的基础上,从实战出发,继续协程之旅。 在Kotlin中,要想使用协程,首先需要使用协程创建器创建,但还有个前提——协程作用域( CoroutineScope )。在早期的Kotlin实现中,协程创建器是一等函数,也就是说我们随

    2024年02月09日
    浏览(42)
  • Android Kotlin 协程初探

    维基百科:协程,英文Coroutine [kəru’tin] (可入厅),是计算机程序的一类组件,推广了协作式多任务的子程序,允许执行被挂起与被恢复。 作为Google钦定的Android开发首选语言Kotlin,协程并不是 Kotlin 提出来的新概念,目前有协程概念的编程语言有Lua语言、Python语言、Go语言

    2024年02月08日
    浏览(45)
  • Kotlin 协程基础使用学习

    原文: Kotlin 协程基础使用学习-Stars-One的杂货小窝 本篇阅读可能需要以下知识,否则可能阅读会有些困难 客户端开发基础(Android开发或JavaFx开发) Java多线程基础 kotlin基础 本文尽量以使用为主,以代码为辅讲解,不提及过深协程底层代码逻辑,仅做一个基础入门来快速上手学习(断断

    2024年03月18日
    浏览(59)
  • 协程 VS 线程,Kotlin技术精讲

    协程(coroutines)是一种并发设计模式,您可以在Android 平台上使用它来简化异步执行的代码。协程是在版本 1.3 中添加到 Kotlin 的,它基于来自其他语言的既定概念。 在 Android 上,协程有助于管理长时间运行的任务,如果管理不当,这些任务可能会阻塞主线程并导致应用无响应。

    2024年02月09日
    浏览(37)
  • kotlin协程async与await

    kotlin协程async与await 输出: 3 3072 https://zhangphil.blog.csdn.net/article/details/129265638 https://zhangphil.blog.csdn.net/article/details/129265638 kotlin协程、线程切换,函数方法委托_zhangphil的博客-CSDN博客 runBlocking 内部启动的3个协程做耗时操作,从输出可以看到3个协程交叉并发执行,runBlocking 会等

    2024年02月05日
    浏览(37)
  • 【Kotlin】协程的字节码原理

    前言 协程是Koltin语言最重要的特性之一,也是最难理解的特性。网上关于kotlin协程的描述也是五花八门,有人说它是轻量级线程,有人说它是无阻塞式挂起,有人说它是一个异步框架等等,众说纷芸。甚至还有人出了书籍专门介绍kotlin协程。 笔者刚开始接触这个概念也是一

    2024年01月18日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包