Kotlin中使用协程简单记录

Android 8个月前更新 biumall.com站长 32
共计 2805 个字符,预计 8 分钟能阅读完成

前言

虽然学习了Kotlin协程,但总忘记怎么使用了,因此简单的记录于此,方便自己查阅和回顾。

在开发程序时会遇到一些耗时的操作,如网络IO、文件IO、CPU/GPU密集型任务等,这些操作会阻塞线程直到操作完成。线程阻塞问题,在Kotlin中除了通过开启新线程来解决外,还可以使用协程来解决。

正文

协程和线程

特性 协程 (Coroutines) 传统线程 (Threads)
资源消耗 极低(单线程可运行大量协程) 较高(每个线程需要约1MB内存)
切换开销 小(在用户态由程序控制,无需内核介入) 大(需要系统内核进行线程调度)
编码风格 同步式顺序编码,避免回调地狱 常需回调或复杂同步机制,易产生嵌套
生命周期管理 提供结构化并发,可轻松绑定到组件生命周期 通常需手动管理,相对复杂

协成

协程主要特点:

  1. 协程挂起:协程提供了一种使程序避免阻塞且更廉价可控的操作,叫作协程挂起,协程挂起不阻塞线程

  2. 简化代码:协程让原来使用“异步+回调”方式写出来的复杂代码,简化成可以用看似同步的方式表达

依赖

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
suspend fun suspendTest() {
    coroutineScope {
        launch {
            //略
        }
    }
}

有suspend标志

Suspend function 'suspend fun suspendTest(): Unit' can only be called from a coroutine or another suspend function.

执行在协成中

runBlocking {
    suspendTest()
}
CoroutineScope
CoroutineScope(Dispatchers.IO).launch {
    Log.d(TAG, "launch 2 : ")
}

其中参数还可以有如下

1. Default
2. Main
3. IO
4. Unconfined

根据上面参数而定

  1. Default 默认子线程

  2. Main 主线程

  3. IO 子线程

  4. Unconfined 根据当前运行环境。如果在主线程找那个调用,运行在主线程;反之,子线程。

GlobalScope
GlobalScope.launch {
    //
}

运行在子线程。

不推荐使用 GlobalScope启动协程,因为 GlobalScope 启动的协程生命周期与应用程序的生命周期一致,无法取消。

MainScope

官方建议在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()
    }
}
区别

简单对比一下常用的几个之间的区别

特性 CoroutineScope() GlobalScope runBlocking coroutineScope
作用域大小 受scope限制 全局 当前线程 当前协程
线程阻塞
自动取消
适用场景 组件生命周期管理 全局任务 测试 suspend函数

参考文章

部分内容来源如下

  1. Kotlin 协程一 —— 协程 Coroutine

  2. Kotlin协程(四)协程CoroutineScope作用域

  3. 腾讯元宝

  4. 百度AI助手

暂无评论

评论审核已启用。您的评论可能需要一段时间后才能被显示。

none
暂无评论...