Kotlin-协程使用

class MediaSelectActivity : BaseActivity() {
    private val videoInfoViewModel by lazy { ViewModelProvider(this).get(VideoInfoViewModel::class.java) }
    private fun initData() {
        videoInfoViewModel.getSystemVideos(contentResolver)
    }
}

class VideoInfoViewModel : ViewModel() {
    val getSystemVideosLiveData: MutableLiveData<List<MediaInfo>> by lazy { MutableLiveData<List<MediaInfo>>() }
    private val model by lazy { VideoInfoModel() }

    fun getSystemVideos(contentResolver: ContentResolver) {
        viewModelScope.launch {
            getSystemVideosLiveData.value = model.getSystemVideos(contentResolver)
        }
    }
}

class VideoInfoModel {
    suspend fun getSystemVideos(contentResolver: ContentResolver) = withContext(Dispatchers.IO) {
        VideoInfoUtils.getSystemVideos(contentResolver)
    }
}

执行过程概述如下:

  1. 应用从主线程上的 View 层 MediaSelectActivity 调用 ViewModel 层 getSystemVideos 函数;

  2. getSystemVideos 函数 会使用 viewModelScope 作用域 launch 创建一个新协程;

  3. Model 层使用 withContext(Dispatchers.IO) 在为 I/O 操作预留的线程上,阻塞执行耗时请求;

  4. suspend 方法执行结束后,将返回值返回给主线程上的 View 层调用处。

1 CoroutineScope 指定协程作用域

  • CoroutineScope 会跟踪它使用 launch 或 async 创建的所有协程,所有协程都必须在一个作用域内运行;

  • 一个 CoroutineScope 管理一个或多个相关的协程;

  • 与调度程序不同,CoroutineScope 不运行协程。

1.1 分类

  • GlobalScope:全局协程作用域,在这个范围内启动的协程可以一直运行直到应用停止运行;本身不会阻塞当前线程,且启动的协程相当于守护线程,不会阻止 JVM 结束运行

  • runBlocking:一个顶层函数,和 GlobalScope 不一样,它会阻塞当前线程直到其内部所有相同作用域的协程执行结束

    扫描二维码关注公众号,回复: 14993204 查看本文章
  • coroutineScope:用于创建一个独立的协程作用域,直到所有启动的协程都完成后才结束自身;runBlocking 方法会阻塞当前线程,而 coroutineScope不会,而是会挂起并释放底层线程以供其它协程使用;runBlocking 是一个普通函数,而 coroutineScope 是一个挂起函数

  • CoroutineScope:自定义协程作用域,如:CoroutineScope(Dispatchers.Main).launch { }

  • lifecycleScope:Lifecycle 中使用,Activity 和 Fragment 等使用

  • viewModelScope:ViewModel中使用,预定义的CoroutineScope,包含在 KTX 扩展中

2 withContext 指定执行协程的线程

  • Dispatchers.Main - 在 Android 主线程上运行协程

  • Dispatchers.IO - 此调度程序经过了专门优化,适合在主线程之外执行磁盘或网络 I/O

  • Dispatchers.Default - 此调度程序经过了专门优化,适合在主线程之外执行占用大量 CPU 资源的工作

如:withContext(Dispatchers.IO)创建一个在 IO 线程池中运行的块。

3 launch 启动协程

        创建协程并将其函数主体的执行分派给相应的调度程序。

4 suspend 挂起函数

  • suspend 用于暂停执行当前协程,并保存所有局部变量

  • resume 用于让已暂停的协程从暂停处继续执行

  • 只能从其他 suspend 函数进行调用,或通过使用协程构建器(例如 launch)来启动新的协程

  • 挂起函数不会阻塞其所在线程,而是会将协程挂起,在特定的时候才再恢复执行

kotlinx.coroutines.Delay 下的 delay() 函数就是一个 suspend 修饰的挂起函数,如下:

public suspend fun delay(time: Long)

        delay() 函数类似于 Java 中的 Thread.sleep(),但它和单纯的线程休眠不同的是,delay() 函数是非阻塞的。

        例如,当在 ThreadA 上运行的 CoroutineA 调用了delay(1000L)函数指定延迟一秒后再运行,ThreadA 会转而去执行 CoroutineB,等到一秒后再来继续执行 CoroutineA。而使用Thread.sleep()的话,线程就只能干等着而不能去执行其它任务。

5 常见搭配

  • CoroutineScope(Dispatchers.Main).launch { }

  • GlobalScope.launch {}

  • lifecycleScope.launch { }

  • viewModelScope.launch { }

参考

【https://developer.android.com/kotlin/coroutines/coroutines-adv?hl=zh-cn】

【https://www.kotlincn.net/docs/reference/coroutines/coroutine-context-and-dispatchers.html】

【https://juejin.cn/post/6908271959381901325#heading-32】

【https://juejin.cn/post/6953441828100112392】

【https://toutiao.io/posts/vtq5kjj/preview】

猜你喜欢

转载自blog.csdn.net/Agg_bin/article/details/128900419