Kotlin协程的简单用法(GlobalScope、lifecycleScope、viewModelScope)

68 篇文章 2 订阅
54 篇文章 3 订阅

协程(Coroutine)

协程就像非常轻量级的线程。线程是由系统调度的,线程切换或线程阻塞的开销都比较大。而协程依赖于线程,但是协程挂起时不需要阻塞线程,协程是由开发者控制的。所以协程也像用户态的线程,非常轻量级,一个线程中可以创建任意个协程。
协程就像轻量级的线程。线程由系统调度,协程由开发者控制。
kotlin协程本质上是对线程池的封装
协程通过将线程切换的复杂性封装入库来简化异步编程。程序的逻辑可以在协程中顺序地表达,而底层库会为我们解决其异步性。
 

GlobalScope(不推荐)

  • GlobalScope.launch
    使用的是DefaultDispatcher,会自动切换到后台线程,不能做UI操作
        GlobalScope.launch {
        	//GlobalScope开启协程:DefaultDispatcher-worker-1
         	Log.d(TAG, "GlobalScope开启协程:" + Thread.currentThread().name)
			//子线程中此处不可以做UI操作
			//Toast.makeText(this@MainActivity, "GlobalScope开启协程", Toast.LENGTH_SHORT).show()
           
        }
  • 可以在协程中切换线程
        GlobalScope.launch {
        	//GlobalScope开启协程:DefaultDispatcher-worker-1
         	Log.d(TAG, "GlobalScope开启协程:" + Thread.currentThread().name)
			//子线程中此处不可以做UI操作
			//Toast.makeText(this@MainActivity, "GlobalScope开启协程", Toast.LENGTH_SHORT).show()
			withContext(Dispatchers.Main){
                Toast.makeText(this@MainActivity, "协程中切换线程", Toast.LENGTH_SHORT).show()
            }
        }
  • GlobalScope.launch(Dispatchers.Main)
    通过Dispatchers.Main使协程依托于主线程中,此时可以更新UI等操作
        GlobalScope.launch(Dispatchers.Main) {
        	//GlobalScope开启协程:main
            Log.d(TAG, "GlobalScope开启协程:" + Thread.currentThread().name)
            //可以做UI操作
            Toast.makeText(this@MainActivity, "GlobalScope开启协程", Toast.LENGTH_SHORT).show()
        }

lifecycleScope、viewModelScope(推荐)

  • 引入方式
    implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.2.0'//lifecycleScope
    implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'//viewModelScope

GlobalScope是生命周期是process级别的,即使Activity或Fragment已经被销毁,协程仍然在执行。所以需要绑定生命周期。
lifecycleScope只能在Activity、Fragment中使用,会绑定Activity和Fragment的生命周期
viewModelScope只能在ViewModel中使用,绑定ViewModel的生命周期

协程的执行顺序

    private fun test() {
        Log.d(TAG, "test: 方法开始")
        lifecycleScope.launch {
            delay(1000)
            Log.d(TAG, "test: " + Thread.currentThread().name)
            Log.d(TAG, "test: 协程结束")
            Toast.makeText(this@MainActivity, "协程结束", Toast.LENGTH_SHORT).show()
        }
        Log.d(TAG, "test: 方法结束")
    }
D/MainActivity: test: 方法开始
D/MainActivity: test: 方法结束
D/MainActivity: test: main
D/MainActivity: test: 协程结束

  • 协程内的阻塞不会影响协程外
  • 由打印结果可以看出协程体是异步执行的,但是可以在其中做UI操作。线程也是异步的,但是不能更新UI,线程需要先切换到主线程。

协程中多个耗时任务的串行

  • 默认情况下协程中的内容是串行的
    private fun test2() {
        lifecycleScope.launch {
            val startTime = System.currentTimeMillis()
            val a = getDataA()
            val b = getDataB()
            val sum = a + b
            //D/MainActivity: test2: sum = 3,耗时:3008
            Log.d(TAG, "test2: sum = $sum,耗时:${System.currentTimeMillis() - startTime}")
        }
    }

    private suspend fun getDataA(): Int {
        delay(1000)
        return 1
    }

    private suspend fun getDataB(): Int {
        delay(2000)
        return 2
    }
D/MainActivity: test2: sum = 3,耗时:3008

协程中多个耗时任务的并行

  • 如果需要并行,例如请求多个接口拿到数据后才能进行操作
    private fun test3(){
        lifecycleScope.launch {
            val startTime = System.currentTimeMillis()
            val a = lifecycleScope.async { getDataA() }
            val b = lifecycleScope.async { getDataB() }
            val sum = a.await() + b.await()
            //D/MainActivity: test3: sum = 3,耗时:2009
            Log.d(TAG, "test3: sum = $sum,耗时:${System.currentTimeMillis() - startTime}")
        }
    }
    
    private suspend fun getDataA(): Int {
        delay(1000)
        return 1
    }

    private suspend fun getDataB(): Int {
        delay(2000)
        return 2
    }

D/MainActivity: test3: sum = 3,耗时:2009

协程的停止

  • 手动停止的情况 job?.cancel()
    private var job: Job? = null

    private fun test4() {
        job = lifecycleScope.launch {
            ...
        }
        job?.cancel()
    }

  • lifecycleScope和viewModelScope会绑定调用者的生命周期,因此通常情况下不需要手动去停止

suspend协程挂起原理

  • 在编译期,将suspend标记的方法转化成接口回调的方式,本质上还是基于回调实现的。

————————————————
版权声明:本文为CSDN博主「张雨zy」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/yu540135101/article/details/113246177

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值