Kotlin学习手记——协程进阶,开源新作

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

如果是应用的话,主要掌握框架级别的使用即可,语言级别的支持api来源于标准库,写起来比较麻烦也非常难理解。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

这里launch会进行一次调度 ,delay会进行一次调度,每次调度完成会执行一次resume, 最终协程体执行完毕会执行一次resume, 所以内部有n个挂起点的协程体会执行n+2次resume.

在这里插入图片描述

DEFAULT 立即开始调度 和 UNDISPATCHED 立即开始执行协程体,这两个含义的区别是 DEFAULT 只是立即启动协程执行可能是异步的,而后者是直接执行协程体中的代码了。LAZY 是先创建协程体,然后在未来的某个时刻才去启动执行。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

UNDISPATCHED 立即开始执行协程体,如果遇到挂起点,就切回主流程了,后面的协程体继续执行在单独的调度器。

import kotlinx.coroutines.*

@ExperimentalCoroutinesApi

suspend fun main() {

println(“start”)

testDefaultMode()

// testAtomicMode()

// testLazyMode()

// testUNDISPATCHEDMode()

println(“finish”)

}

suspend fun testDefaultMode() {

val defaultMode = GlobalScope.launch(start = CoroutineStart.DEFAULT) {

println(“aaa”)

delay(3000)

println(“bbb”)

}

println(“222”)

defaultMode.join()

}

@ExperimentalCoroutinesApi

suspend fun testAtomicMode() {

val defaultMode = GlobalScope.launch(start = CoroutineStart.ATOMIC) {

println(“aaa”)

delay(3000)

println(“bbb”)

}

println(“222”)

defaultMode.join()

}

suspend fun testLazyMode() {

val defaultMode = GlobalScope.async(start = CoroutineStart.LAZY) {

println(“aaa”)

delay(3000)

println(“bbb”)

}

println(“222”)

defaultMode.await()

}

@ExperimentalCoroutinesApi

suspend fun testUNDISPATCHEDMode() {

val defaultMode = GlobalScope.launch(start = CoroutineStart.UNDISPATCHED) {

println(“aaa”)

delay(3000)

println(“bbb”)

}

println(“222”)

defaultMode.join()

}

在这里插入图片描述

Default和IO线程的区别,IO内部多了一个队列的维护

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

回调转协程的完整写法:

import com.bennyhuo.kotlin.coroutines.advanced.common.gitHubServiceApi

import kotlinx.coroutines.suspendCancellableCoroutine

import retrofit2.Call

import retrofit2.Callback

import retrofit2.HttpException

import retrofit2.Response

import kotlin.coroutines.resume

import kotlin.coroutines.resumeWithException

suspend fun Call.await(): T = suspendCancellableCoroutine { //可取消

continuation ->

continuation.invokeOnCancellation {

cancel() //调用retrofit的取消方法

}

enqueue(object: Callback {

override fun onFailure(call: Call, t: Throwable) {

continuation.resumeWithException(t)

}

override fun onResponse(call: Call, response: Response) {

response.takeIf { it.isSuccessful }?.body()?.also {continuation.resume(it) }

?: continuation.resumeWithException(HttpException(response))

}

})

}

suspend fun main() {

val user = gitHubServiceApi.getUserCallback(“flycumt”).await()

println(user)

}

也可以不自己写,retrofit的api中本身有实现await()方法,awaitResponse()方法等。

CompletableFuture 添加回调的写法:

import com.bennyhuo.kotlin.coroutines.advanced.utils.log

import kotlinx.coroutines.suspendCancellableCoroutine

import java.util.concurrent.CompletableFuture

import java.util.concurrent.ExecutionException

import kotlin.coroutines.resume

import kotlin.coroutines.resumeWithException

suspend fun main() {

val result = CompletableFuture.supplyAsync {

3

}.await()

log(result)

}

suspend fun CompletableFuture.await(): T {

if(isDone){

try {

return get()

} catch (e: ExecutionException) {

throw e.cause ?: e

}

}

return suspendCancellableCoroutine { //可取消

cancellableContinuation ->

cancellableContinuation.invokeOnCancellation {

cancel(true) //取消

}

whenComplete { value, throwable ->

if(throwable == null){

cancellableContinuation.resume(value)

} else {

cancellableContinuation.resumeWithException(throwable.cause ?: throwable)

}

}

}

}

CompletableFuture本身也有实现await()方法。

模仿给Handler扩展添加可取消的支持:

suspend fun Handler.run(block: () -> T) = suspendCoroutine { continuation ->

post {

try {

continuation.resume(block())

} catch (e: Exception) {

continuation.resumeWithException(e)

}

}

}

suspend fun Handler.runDelay(delay: Long, block: () -> T) = suspendCancellableCoroutine { continuation ->

val message = Message.obtain(this) { //Message obtain(Handler h, Runnable callback)

try {

continuation.resume(block())

} catch (e: Exception){

continuation.resumeWithException(e)

}

}.also {

it.obj = continuation //message.obj

}

continuation.invokeOnCancellation {

removeCallbacksAndMessages(continuation) //通过Handler的removeCallbacksAndMessages方法来取消回调, 参数就是前面设置的message.obj的值

}

sendMessageDelayed(message, delay)

}

suspend fun main() {

Looper.prepareMainLooper()

GlobalScope.launch {

val handler = Handler(Looper.getMainLooper())

val result = handler.run { “Hello” }

val delayedResult = handler.runDelay(5000){ “World” }

log(result, delayedResult)

Looper.getMainLooper().quit()

}

Looper.loop()

}

这个例子的主要意图是,Hanlder可以通过定义扩展函数的方式来延时获取一些东西,比如Activity刚创建的时候,拿不到view的宽和高,就可以使用这种方法。

上面三个例子主要是针对可取消的写法,如果实际用,不用自己写,直接导库就行。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

其中CONFLATED比较适合用于状态更新,比如进度条的进度,因为它总是只取最新的。

在这里插入图片描述

在这里插入图片描述

关闭后再发送会抛异常:

在这里插入图片描述

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)

}

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

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

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

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题 (含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总)

面试成功其实是必然的,因为我做足了充分的准备工作,包括刷题啊,看一些Android核心的知识点,看一些面试的博客吸取大家面试的一些经验,下面这份PDF是我翻阅了差不多1个月左右一些Android大博主的博客从他们那里取其精华去其糟泊所整理出来的一些Android的核心知识点, 全部都是精华中的精华,我能面试到现在资深开发人员跟我整理的这本Android核心知识点有密不可分的关系,在这里本着共赢的心态分享给各位朋友。

这份PDF囊括了JVM,Java集合,Java多线程并发,Java基础,生命周期,微服务, 进程,Parcelable 接口,IPC,屏幕适配,线程异步,ART,架构,Jetpack,NDK开发,计算机网络基础,类加载器,Android 开源库源码分析,设计模式汇总,Gradle 知识点汇总…

由于篇幅有限,就不做过多的介绍,大家请自行脑补

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

战项目、讲解视频,并且会持续更新!**

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题 (含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总)

[外链图片转存中…(img-5ueDEpT3-1712778652197)]

面试成功其实是必然的,因为我做足了充分的准备工作,包括刷题啊,看一些Android核心的知识点,看一些面试的博客吸取大家面试的一些经验,下面这份PDF是我翻阅了差不多1个月左右一些Android大博主的博客从他们那里取其精华去其糟泊所整理出来的一些Android的核心知识点, 全部都是精华中的精华,我能面试到现在资深开发人员跟我整理的这本Android核心知识点有密不可分的关系,在这里本着共赢的心态分享给各位朋友。
[外链图片转存中…(img-O5GNKQjO-1712778652197)]

这份PDF囊括了JVM,Java集合,Java多线程并发,Java基础,生命周期,微服务, 进程,Parcelable 接口,IPC,屏幕适配,线程异步,ART,架构,Jetpack,NDK开发,计算机网络基础,类加载器,Android 开源库源码分析,设计模式汇总,Gradle 知识点汇总…

由于篇幅有限,就不做过多的介绍,大家请自行脑补

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 29
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 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、付费专栏及课程。

余额充值