虽然学习了Kotlin的协程,但总忘记怎么使用了,因此简单的记录于此,方便自己查阅和回顾。
在开发程序时会遇到一些耗时的操作,如网络IO、文件IO、CPU/GPU密集型任务等,这些操作会阻塞线程直到操作完成。线程阻塞问题,在Kotlin中除了通过开启新线程来解决外,还可以使用协程来解决。
正文
协程和线程
特性 | 协程 (Coroutines) | 传统线程 (Threads) |
---|---|---|
资源消耗 | 极低(单线程可运行大量协程) | 较高(每个线程需要约1MB内存) |
切换开销 | 小(在用户态由程序控制,无需内核介入) | 大(需要系统内核进行线程调度) |
编码风格 | 同步式顺序编码,避免回调地狱 | 常需回调或复杂同步机制,易产生嵌套 |
生命周期管理 | 提供结构化并发,可轻松绑定到组件生命周期 | 通常需手动管理,相对复杂 |
协成
协程主要特点:
协程挂起:协程提供了一种使程序避免阻塞且更廉价可控的操作,叫作协程挂起,协程挂起不阻塞线程
简化代码:协程让原来使用“异步+回调”方式写出来的复杂代码,简化成可以用看似同步的方式表达
依赖
build.gradle文件中添加依赖
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3") //Android项目 implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
启动
在Kotlin程序中,启动一个协程的方式有很多种,例如通过launch()函数、runBlocking()函数等方式来启动一个协程,最常用的方式是通过launch()函数来启动协程。
lifecycleScope
需要再AppCompatActivity类中
lifecycleScope.launch { Log.d(TAG, "launch 1 : ") }
runBlocking
runBlocking { Log.d(TAG, "launch 2 : ") }
CoroutineScope
CoroutineScope(Dispatchers.IO).launch { Log.d(TAG, "launch 2 : ") }
其中参数还可以有如下
1. Default 2. Main 3. IO 4. Unconfined
MainScope
不要使用 GlobalScope 去启动协程,因为 GlobalScope 启动的协程生命周期与应用程序的生命周期一致,无法取消。
官方建议在Android中自定义协程作用域,当然Kotlin提供了MainScope,让我们直接使用。
public fun MainScope(): CoroutineScope = ContextScope(SupervisorJob() + Dispatchers.Main)
class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() { //略 }
使用launch或async
launch { //main线程 val test = async { //DefaultDispatcher-worker-1 工作线程 delay(1000) "test" } }
最后别忘了,在 Activity onDestory 时取消协程。
override fun onDestroy() {
cancel()
super.onDestroy()
}
ViewModelScope
如果你使用了 ViewModel + LiveData 实现 MVVM 架构,根本就不会在 Activity 上书写任何逻辑代码,更别说启动协程了。这个时候大部分工作就要交给 ViewModel 了。那么如何在 ViewModel 中定义协程作用域呢?
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.async import kotlinx.coroutines.delay import kotlinx.coroutines.launch class ViewModelOne : ViewModel() { private val viewModelJob = SupervisorJob() private val uiScope = CoroutineScope(Dispatchers.Main + viewModelJob) val mMessage: MutableLiveData<String> = MutableLiveData() fun getMessage(message: String) { uiScope.launch { val deferred = async(Dispatchers.IO) { delay(2000) "post $message" } mMessage.value = deferred.await() } } override fun onCleared() { super.onCleared() viewModelJob.cancel() } }
参考文章
《》
《腾讯元宝》
历史上的今天
- 《Kotlin中使用协程简单记录》
- 《Kotlin之子类和子类型》
- 《久久韩剧网》
- 《饭团影视》
- 《网易娱乐》
- 《神马电影网》
- 《影视之家》
- 《蓝光影院》
- 《看看电影》