Kotlin学习手记——协程进阶,带你轻松理解Android-Hook机制

在这里插入图片描述

在这里插入图片描述

关闭后再发送会抛异常:

在这里插入图片描述

channel关闭后,channel中的数据仍然可以被接受,只有当channel中的数据消费完了,isClosedForReceive才为true.

在这里插入图片描述

suspend fun main() {

basics()

}

suspend fun basics() {

val channel = Channel(Channel.RENDEZVOUS)

// val channel = Channel(Channel.UNLIMITED)

// val channel = Channel(Channel.CONFLATED)

// val channel = Channel(Channel.BUFFERED)

// val channel = Channel(1)

//生产者 发

val producer = GlobalScope.launch {

for (i in 0…3) {

log(“sending”, i)

channel.send(i)

log(“sent”, i)

}

channel.close()

}

//消费者 收

val consumer = GlobalScope.launch {

while (!channel.isClosedForReceive) {

log(“receiving”)

val value = channel.receiveOrNull()

log(“received”, value)

}

}

producer.join()

consumer.join()

}

Channel(Channel.RENDEZVOUS ) 的方式是发一个收一个,边发边收,如果没有接受的,发送者会挂起等待,输出如下:

在这里插入图片描述

Channel(Channel.UNLIMITED ) 的方式是全部发送完毕,才会接收到,先发后收,发送者发送完就返回了,不管有没有接受者,输出如下:在这里插入图片描述

Channel(Channel.CONFLATED ) 的方式是不管发了多少个,只能收到最后一个,也是发送完就返回了,不管有没有接受者,输出如下:

在这里插入图片描述

Channel(Channel.BUFFERED ) 的方式也是发送者发送完就返回了,不管有没有接受者,可以指定buffer大小,输出如下:

在这里插入图片描述

Channel(1) 的方式指定管道的容量大小,如果数据超过容量,发送者就会挂起等待,直到有接受者取走数据,发送者才发送下一批数据,

在这里插入图片描述

在这里插入图片描述

channel接受数据的时候可以直接当成迭代器使用:

suspend fun iterateChannel() {

val channel = Channel(Channel.UNLIMITED)

val producer = GlobalScope.launch {

for (i in 0…3) {

log(“sending”, i)

channel.send(i)

log(“sent”, i)

}

channel.close()

}

val consumer = GlobalScope.launch {

for (i in channel) {

log("received: ", i)

}

}

producer.join()

consumer.join()

}

在这里插入图片描述

suspend fun producer() {

val receiveChannel = GlobalScope.produce(capacity = Channel.UNLIMITED) {

for (i in 0…3) {

log(“sending”, i)

send(i)

log(“sent”, i)

}

}

val consumer = GlobalScope.launch {

for (i in receiveChannel) {

log("received: ", i)

}

}

consumer.join()

}

suspend fun consumer() {

val sendChannel = GlobalScope.actor(capacity = Channel.UNLIMITED) {

for (i in this) {

log("received: ", i)

}

}

val producer = GlobalScope.launch {

for (i in 0…3) {

log(“sending”, i)

sendChannel.send(i)

log(“sent”, i)

}

}

producer.join()

}

在这里插入图片描述

在这里插入图片描述

suspend fun broadcast() {

//下面几种都可以创建一个BroadcastChannel

//val broadcastChannel = BroadcastChannel(Channel.BUFFERED)

//val broadcastChannel = Channel(Channel.BUFFERED).broadcast()

val broadcastChannel = GlobalScope.broadcast {

for (i in 0…5) {

send(i)

}

}

//启动5个接受者,每个都能收到

List(5) { index ->

GlobalScope.launch {

val receiveChannel = broadcastChannel.openSubscription()

for (i in receiveChannel) {

log(“[#$index] received: $i”)

}

}

}.joinAll()

}

输出:

Task :ChannelsKt.main()

21:07:12:924 [DefaultDispatcher-worker-3 @coroutine#2] [#0] received: 0

21:07:12:924 [DefaultDispatcher-worker-5 @coroutine#6] [#4] received: 0

21:07:12:924 [DefaultDispatcher-worker-1 @coroutine#3] [#1] received: 0

21:07:12:925 [DefaultDispatcher-worker-4 @coroutine#5] [#3] received: 0

21:07:12:925 [DefaultDispatcher-worker-2 @coroutine#4] [#2] received: 0

21:07:12:944 [DefaultDispatcher-worker-1 @coroutine#3] [#1] received: 1

21:07:12:943 [DefaultDispatcher-worker-3 @coroutine#2] [#0] received: 1

21:07:12:943 [DefaultDispatcher-worker-5 @coroutine#6] [#4] received: 1

21:07:12:944 [DefaultDispatcher-worker-4 @coroutine#5] [#3] received: 1

21:07:12:945 [DefaultDispatcher-worker-2 @coroutine#4] [#2] received: 1

21:07:12:945 [DefaultDispatcher-worker-2 @coroutine#4] [#2] received: 2

21:07:12:945 [DefaultDispatcher-worker-8 @coroutine#3] [#1] received: 2

21:07:12:945 [DefaultDispatcher-worker-8 @coroutine#3] [#1] received: 3

21:07:12:945 [DefaultDispatcher-worker-7 @coroutine#4] [#2] received: 3

21:07:12:945 [DefaultDispatcher-worker-2 @coroutine#6] [#4] received: 2

21:07:12:946 [DefaultDispatcher-worker-2 @coroutine#6] [#4] received: 3

21:07:12:946 [DefaultDispatcher-worker-8 @coroutine#5] [#3] received: 2

21:07:12:946 [DefaultDispatcher-worker-8 @coroutine#5] [#3] received: 3

21:07:12:946 [DefaultDispatcher-worker-3 @coroutine#2] [#0] received: 2

21:07:12:946 [DefaultDispatcher-worker-3 @coroutine#2] [#0] received: 3

21:07:12:946 [DefaultDispatcher-worker-1 @coroutine#3] [#1] received: 4

21:07:12:946 [DefaultDispatcher-worker-3 @coroutine#2] [#0] received: 4

21:07:12:946 [DefaultDispatcher-worker-1 @coroutine#6] [#4] received: 4

21:07:12:947 [DefaultDispatcher-worker-6 @coroutine#5] [#3] received: 4

21:07:12:947 [DefaultDispatcher-worker-6 @coroutine#5] [#3] received: 5

21:07:12:947 [DefaultDispatcher-worker-2 @coroutine#3] [#1] received: 5

21:07:12:947 [DefaultDispatcher-worker-6 @coroutine#2] [#0] received: 5

21:07:12:947 [DefaultDispatcher-worker-2 @coroutine#6] [#4] received: 5

21:07:12:947 [DefaultDispatcher-worker-3 @coroutine#4] [#2] received: 4

21:07:12:947 [DefaultDispatcher-worker-3 @coroutine#4] [#2] received: 5

在这里插入图片描述

在这里插入图片描述

Select的使用场景是多个协程异步执行时,获取最先结束的那个协程结果返回,比如加载图片时,可能从网络获取,也可能从本地获取,这两种可能同时异步执行,使用Select就会优先获取返回比较快的本地结果展示,然后我们再去获取网络最新的更新即可。

在这里插入图片描述

使用例子:

val localDir = File(“localCache”).also { it.mkdirs() }

val gson = Gson()

fun CoroutineScope.getUserFromApi(login: String) = async(Dispatchers.IO){

gitHubServiceApi.getUserSuspend(login)

}

fun CoroutineScope.getUserFromLocal(login:String) = async(Dispatchers.IO){

File(localDir, login).takeIf { it.exists() }?.readText()?.let { gson.fromJson(it, User::class.java) }

}

fun cacheUser(login: String, user: User){

File(localDir, login).writeText(gson.toJson(user))

}

data class Response(val value: T, val isLocal: Boolean)

suspend fun main() {

val login = “test”

GlobalScope.launch {

val localDeferred = getUserFromLocal(login)

val remoteDeferred = getUserFromApi(login)

//val userResponse = Response(localDeferred.await(), true)

//select选择优先返回的结果

val userResponse = select<Response<User?>> {

localDeferred.onAwait { Response(it, true) }

remoteDeferred.onAwait { Response(it, false) }

}

userResponse.value?.let { log(it) } //获取结果显示 输出

//如果是本地的结果,重新请求,并缓存本地

userResponse.isLocal.takeIf { it }?.let {

val userFromApi = remoteDeferred.await()

cacheUser(login, userFromApi)

log(userFromApi)

}

}.join()

}

如果有多个异步请求同时返回,select会按顺序取第一个,想要随机的取可以使用selectUnbiased

在这里插入图片描述

select大括号中onAwait的写法等价于 await() 的写法,localDeferred.await(),还有很多操作join send等都是一样的前面加on

在这里插入图片描述

例子:使用channel和select实现统计代码行数

val KotlinFileFilter = { file: File -> file.isDirectory || file.name.endsWith(“.kt”) }

data class FileLines(val file: File, val lines: Int) {

override fun toString(): String {

return “${file.name}: $lines”

}

}

suspend fun main() {

val result = lineCounter(File(“.”))

log(result)

}

suspend fun lineCounter(root: File): HashMap<File, Int> {

return Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() + 1).asCoroutineDispatcher()

//使用use自动关闭资源

.use {

//withContext是一个挂起函数 返回值是最后一行表达式的值

withContext(it){

val fileChannel = walkFile(root)

//定义5个同时读取

val fileLinesChannels = List(5){

fileLineCounter(fileChannel)

}

resultAggregator(fileLinesChannels)

}

}

}

//创建生产者返回ReceiveChannel

fun CoroutineScope.walkFile(root: File): ReceiveChannel {

return produce(capacity = Channel.BUFFERED) {

fileWalker(root)

}

}

//递归过滤kotlin文件并发送文件

suspend fun SendChannel.fileWalker(file: File) {

if(file.isDirectory){

file.listFiles()?.filter(KotlinFileFilter)?.forEach { fileWalker(it) }

} else {

send(file)

}

}

//输入File 返回FileLines对象

fun CoroutineScope.fileLineCounter(input: ReceiveChannel): ReceiveChannel {

return produce(capacity = Channel.BUFFERED) {

for (file in input){

//统计行数

file.useLines {

send(FileLines(file, it.count())) //发送结果

}

}

}

}

suspend fun CoroutineScope.resultAggregator(channels: List<ReceiveChannel>): HashMap<File, Int> {

val map = HashMap<File, Int>()

channels.aggregate {

filteredChannels ->

//使用select返回最快统计的那一个

select<FileLines?> {

filteredChannels.forEach {

it.onReceiveOrNull {

log(“received: $it”)

it

}

}

} ?.let {

map[it.file] = it.lines

}

}

return map

}

//tailrec-递归优化 定义List<ReceiveChannel>的扩展函数,过滤掉已完成的

tailrec suspend fun List<ReceiveChannel>.aggregate(block: suspend (List<ReceiveChannel>) -> Unit) {

block(this)//消费一次

//从当前list中过掉isClosedForReceive=true的ReceiveChannel

filter { !it.isClosedForReceive }.takeIf { it.isNotEmpty() }?.aggregate(block)//递归

}

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
img

写在最后

对程序员来说,很多技术的学习都是“防御性”的。也就是说,我们是在为未来学习。我们学习新技术的目的,或是为了在新项目中应用,或仅仅是为了将来的面试。但不管怎样,一定不能“止步不前”,不能荒废掉。

![
[]


文章以下内容会给出阿里与美团的面试题(答案+解析)、面试题库、Java核心知识点梳理等,需要这些文档资料的,直接点击我的GitHub免费领取~

大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频**
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
[外链图片转存中…(img-nRE32y72-1710667662476)]

写在最后

对程序员来说,很多技术的学习都是“防御性”的。也就是说,我们是在为未来学习。我们学习新技术的目的,或是为了在新项目中应用,或仅仅是为了将来的面试。但不管怎样,一定不能“止步不前”,不能荒废掉。

[外链图片转存中…(img-y7nzh3zX-1710667662476)]

[外链图片转存中…(img-bWDuGjAa-1710667662476)]
[]

[外链图片转存中…(img-wR7Sycw9-1710667662477)]
[外链图片转存中…(img-4y6GC0gh-1710667662477)]

文章以下内容会给出阿里与美团的面试题(答案+解析)、面试题库、Java核心知识点梳理等,需要这些文档资料的,直接点击我的GitHub免费领取~

  • 14
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Kotlin协程是一种轻量级的线程处理机制,它可以在不创建新线程的情况下实现异步操作。Kotlin协程的优势在于它提供了一种结构化并发的方式,使得异步代码更加易于编写和维护。下面是深入理解Kotlin协程的一些方法和步骤: 1. 协程的基本概念:协程是一种轻量级的线程处理机制,它可以在不创建新线程的情况下实现异步操作。协程的本质是一种协作式的多任务处理机制,它可以在同一个线程中切换执行不同的任务,从而实现异步操作。 2. 协程的使用方法:在Kotlin中,协程的使用方法非常简单。首先需要导入kotlinx.coroutines库,然后使用launch函数创建一个协程。在协程中可以使用挂起函数来实现异步操作,例如delay函数可以让协程暂停一段时间。 3. 协程的挂起函数:协程的挂起函数是一种特殊的函数,它可以让协程暂停执行,等待某个条件满足后再继续执行。在Kotlin中,常用的挂起函数包括delay函数、withContext函数和async函数等。 4. 协程的上下文:协程的上下文是一种特殊的对象,它包含了协程的执行环境和状态信息。在Kotlin中,协程的上下文可以通过CoroutineContext对象来表示,它包含了协程的调度器、异常处理器和其他一些属性。 5. 协程的异常处理:协程的异常处理是一种特殊的机制,它可以让协程在发生异常时自动恢复或者终止执行。在Kotlin中,协程的异常处理可以通过try-catch语句或者CoroutineExceptionHandler对象来实现。 6. 协程的取消:协程的取消是一种特殊的机制,它可以让协程在不需要继续执行时自动终止。在Kotlin中,协程的取消可以通过cancel函数或者协程作用域来实现。 下面是一个使用Kotlin协程实现异步操作的例子: ```kotlin import kotlinx.coroutines.* fun main() = runBlocking { val job = launch { delay(1000L) println("World!") } println("Hello,") job.join() } ``` 输出结果为: ``` Hello, World! ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值