前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android Kotlin协程间的通信Channel介绍

Android Kotlin协程间的通信Channel介绍

作者头像
Vaccae
发布2022-05-25 09:07:56
6310
发布2022-05-25 09:07:56
举报
文章被收录于专栏:微卡智享微卡智享

前言

使用Kotlin做Android项目时,肯定少不了使用协程,而在协程的使用中,少不了要在不同的协程中传递数据,而Kotlin中的Channel,就是专门用来处理协程之间的通信,今天这篇就是来看看Channel的用法。

Channel简介

channel用于协程间的通信, 允许我们在不同的协程间传递数据。channel非常类似于一个 java 中非常常见的概念BlockingQueue,元素从一端被加入, 从另一端被消费.。当需要的时候, 多个协程可以向同一个channel发送数据, 一个channel的数据也可以被多个协程接收。当多个协程从同一个channel接收数据的时候, 每个元素仅被其中一个consumer消费一次. 处理元素会自动将其从channel里删除。

Channel的用法

channel可以简单的通过send和receive实现。

代码语言:javascript
复制
fun main() = runBlocking{
    val intchannel = Channel<Int>()
    launch {
        for(x in 1..10) intchannel.send(x)
    }

    repeat(10){ 
        val recv = intchannel.receive()
        println("read:$recv")
    }
}

输出结果

channel还可以通过遍历来实现receive。

代码语言:javascript
复制
fun main() = runBlocking{
    val intchannel = Channel<Int>()
    launch {
        for(x in 1..6) intchannel.send(x)
    }

    for(recv in intchannel) println("read:$recv")
    println("receive finish")
}

输出结果

从上图中可以看到,通过for的方式可以直接赋值到recv里打印出来了,但是在代码的结尾中我们的println("receive finish"),并没有在控制台打印出来,程序也没有退出,这是因为接收者在协程中还一直在等待。

想要正常结束并退出,接下来就要用到channel的关闭了,Channel可以被关闭, 说明没有更多的元素了。取消协程也会关闭channel。那我们改一下上面的代码,加上close。

代码语言:javascript
复制
fun main() = runBlocking{
    val intchannel = Channel<Int>()
    launch {
        for(x in 1..6) intchannel.send(x)
        intchannel.close()
    }

    for(recv in intchannel) println("read:$recv")
    println("receive finish")
}

代码中加入了close后,可以看到,channel接收完后,打印出的finish并且退出程序了。

channel的类型

Channel有四种不同的类型,类型间不同的区别有两点,一是定义内部可以存储的元素,二是Send方式是否可以被挂起;而所有channel类型的Receive方法都是同样的行为,如果channel不为空, 接收一个元素, 否则挂起,具体的类型如下:

  1. Rendezvous channel(默认类型): 0尺寸buffer,Send和Receive要见面,否则Send挂起,就是说每Send完的后,如果一直没有Receive,即被挂起。
  2. Buffered channel:指定元素大小,当满了后Send会被挂起。
  3. Conflated channel: 新元素会覆盖旧元素,receiver只会得到最新元素,Send永不挂起。
  4. Unlimited channel: 无限元素,Send不被挂起。

接下来我们做个用多个协程向同一个Channel发送数据的例子来看看这四种模式。

01Rendezvous channel(默认类型)

代码语言:javascript
复制
fun main() {
    val channel = Channel<String>()
    runBlocking {
        val res1 = async {
            for (x in 1..5) {
                channel.send("I am $x")
            }
            return@async "res1 over"
        }
        val res2 = async {
            for (y in 11..15) {
                channel.send("you are $y")
            }
            return@async "res2 over"
        }
        val res3 = async {
            for (z in 21..25) {
                channel.send("he is $z")
            }
            return@async "res3 over"
        }
        launch {
            println(" async finish ${res1.await() + res2.await() + res3.await()} ")
            channel.close()
        }
        for (item in channel) {
            println(item)
        }

        println("finish")
    }
}

代码中用async开启三个协程,当三个协程执行完后,关闭channel。下面是输出结果。

02Buffered channel

代码语言:javascript
复制
val channel = Channel<String>(3)

当channel中后面加上数字3,然后再运行看。

上图中,因为满了3个后Send挂起,所以第一个协程(1-5)完后,第二个协程的11数字进去后也开始挂起了,这时的挂起也让第三个协程(21-25)的第一条进入到队列中。

03Conflated channel

代码语言:javascript
复制
val channel = Channel<String>(Channel.CONFLATED)

当channel中后面参数加上Channel.CONFLATED,然后再运行看。

可以看到输出的只有两条,第一条数据和最后一条数据。

04Unlimited channel

代码语言:javascript
复制
val channel = Channel<String>(Channel.UNLIMITED)

当channel中后面参数加上Channel.UNLIMITED,然后再运行看。

这里就可以看出,当使用Channel.UNLIMITED时,完全是按钮协程调用的顺序输出的。

Kotlin使用协程时,还是会经常用Channel来处理协程之间的数据通信,更多的用法可以自己去多做尝试

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-05-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 微卡智享 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • Channel简介
    • Channel的用法
      • channel的类型
        • 01Rendezvous channel(默认类型)
        • 02Buffered channel
        • 03Conflated channel
        • 04Unlimited channel
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档