个人博客
http://www.milovetingting.cn
Kotlin的协程
前言
本文是Kotlin协程的一个简单笔记,由于刚接触Kotlin语言,如有理解错误,为避免误导别人,可留言评论,以便本人及时修改,感谢各位大佬!关于协程的进阶文章,可参考其它相关资料!
协程是什么
协程是一种并发设计
模式,在 Android
平台上使用它来简化异步执行
的代码。
以上是官方文档对协程的简单定义。
下面通过代码来展示协程的具体使用。
假设有以下的需求:有一个耗时的任务要执行,在执行完成后,需要在主线程刷新UI。
不使用协程
在Activity的onCreate中分别调用以下方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| io()
ui()
private fun io() { thread { Log.d(TAG, "io method,thread:${Thread.currentThread().name}") delay(1000) } }
private fun ui() { Log.d(TAG, "ui method,thread:${Thread.currentThread().name}") }
|
输出日志:
1 2
| 2020-09-25 23:10:25.854 5208-5208/com.wangyz.coroutines D/Coroutine: ui method,thread:main 2020-09-25 23:10:25.855 5208-5267/com.wangyz.coroutines D/Coroutine: io method,thread:Thread-2
|
分别调用io()和ui()方法,两个方法分别运行在子线程和主线程中,但是由于子线程的耗时操作,主线程方法先执行了,这样就没有达到我们想要的顺序执行的效果。
修改代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| io2()
private fun io2() { thread { Log.d(TAG, "io method,thread:${Thread.currentThread().name}") delay(1000) runOnUiThread { ui2() } } }
private fun ui2() { Log.d(TAG, "ui method,thread:${Thread.currentThread().name}") }
|
在子线程中通过runOnUiThread将线程切换到主线程中来,输出结果:
1 2
| 2020-09-25 23:16:44.753 5597-5641/com.wangyz.coroutines D/Coroutine: io method,thread:Thread-2 2020-09-25 23:16:45.756 5597-5597/com.wangyz.coroutines D/Coroutine: ui method,thread:main
|
再来看下协程的实现方式
使用协程
依赖项信息
如需在Android项目中使用协程,需要将以下依赖项添加到应用的 build.gradle 文件中:
1 2 3
| dependencies { implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9' }
|
协程的使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| GlobalScope.launch(Dispatchers.Main) { io3() ui3() }
private suspend fun io3(){ withContext(Dispatchers.IO){ Log.d(TAG, "io method,thread:${Thread.currentThread().name}") delay(1000) } }
private fun ui3() { Log.d(TAG, "ui method,thread:${Thread.currentThread().name}") }
|
通过launch方法开启一个协程,通过设置Dispatchers.Main运行在Main线程中,在io3中,通过withContext开启一个线程,并通过设置Dispatchers.IO运行在IO线程。suspend是一个标记,表示这个方法内部会有挂起的操作,它并不会导致线程切换,真正切换线程是通过withContext来切换的。
输出结果:
1 2
| 2020-09-25 23:28:19.965 6017-6062/com.wangyz.coroutines D/Coroutine: io method,thread:DefaultDispatcher-worker-1 2020-09-25 23:28:20.969 6017-6017/com.wangyz.coroutines D/Coroutine: ui method,thread:main
|
假设我们需要同时请求多个接口,并在这些接口全部返回数据后再统一更新界面,下面用协程来模拟实现这个需求。
请求多个异步接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| GlobalScope.launch(Dispatchers.Main) { val res1 = async { io4() } val res2 = async { io5() } val data = res1.await() + res2.await() ui4(data) }
private suspend fun io4() = withContext( Dispatchers.IO ) { delay(2000) Log.d(TAG, "io method,thread:${Thread.currentThread().name}") 1 }
private suspend fun io5() = withContext( Dispatchers.IO ) { delay(3000) Log.d(TAG, "io method,thread:${Thread.currentThread().name}") 2 }
private fun ui4(value: Int) { Log.d(TAG, "ui method,thread:${Thread.currentThread().name},result:${value}") }
|
输出结果:
1 2 3
| 2020-09-25 23:51:28.161 6495-6536/com.wangyz.coroutines D/Coroutine: io method,thread:DefaultDispatcher-worker-1 2020-09-25 23:51:29.389 6495-6537/com.wangyz.coroutines D/Coroutine: io method,thread:DefaultDispatcher-worker-2 2020-09-25 23:51:29.390 6495-6495/com.wangyz.coroutines D/Coroutine: ui method,thread:main,result:3
|
方法io4执行2秒,方法io5执行3秒,在io5执行完成后,将他们的结果相加再通过ui4更新到UI上。
参考
https://developer.android.google.cn/kotlin/coroutines