文章目录

前言

虽然学习了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()GlobalScoperunBlockingcoroutineScope
作用域大小受scope限制全局当前线程当前协程
线程阻塞
自动取消
适用场景组件生命周期管理全局任务测试suspend函数

参考文章

部分内容来源如下

  1. Kotlin 协程一 —— 协程 Coroutine

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

  3. 腾讯元宝

  4. 百度AI助手

相关文章

暂无评论

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

none
暂无评论...