Kotlin-协程是什么?

Hi你好,新同窗。很高兴,你终于追寻这个问题了,也许你正感到迷茫,各路大神对协程的理解不一,有人说它是线程框架,有人说它比线程更轻,但愿我这篇博文能够帮你从另外一个角度简单理解协程。html

请相信一句话,任何解释从第二我的口中说出时,可能已经存在了变化。而官网是咱们接触任何技术最必要的门槛。因此请打开Kotlin中文网。不少人说kotlin官网教程很不详细,其实否则,kotlin中文网教程很详细。回到正题:java

什么是协程?

image-20200115165921441

  • 异步编程
  • 体验
  • 语言级
  • 理念

注意上面几个关键点和一些实际使用,不难明白android

Kotlin协程是基于Kotlin语法从而延伸的一个异步编程框架,它并无带来多少性能上的体验,它能实现的,你用线程池一样也能够实现,但对于使用角度的来讲,协程努力打造一个 "同步方式,异步编程的" 思想,做为开发者来讲,咱们能够更懒了,切换线程,withContext便可,协程带来了开发上的温馨,但这种温馨是基于 Kotlin 的语法,并非别的。因此我但愿你们关注协程时,多从语言角度去理解。编程

那么,协程是什么呢?

协程就是一个基于Kotlin语法的异步框架,它可使开发者以同步的方式,写成异步的代码,而无需关注多余操做。就这么简单bash


协程怎么用?

启动一个协程

suspend fun main() {
    GlobalScope.launch {
        println("启动--${System.currentTimeMillis()}---${Thread.currentThread().name}")
        delay(100)
        println("挂起100ms--${System.currentTimeMillis()}---${Thread.currentThread().name}")
    }
    delay(1000)
}
复制代码
启动--1579085375166---DefaultDispatcher-worker-1
挂起100ms--1579085375275---DefaultDispatcher-worker-1
复制代码

并发使用

fun main() {
    runBlocking(Dispatchers.IO) {
        println("启动--${System.currentTimeMillis()}")
        val as1 = async {
            delay(100)
            println("并发1--${System.currentTimeMillis()}---${Thread.currentThread().name}")
            "1"
        }
        val as2 = async {
            delay(100)
            println("并发2--${System.currentTimeMillis()}---${Thread.currentThread().name}")
            "2"
        }
        println("as1=${as1.await()},as2=${as2.await()}")
    }
}
复制代码
启动--1579085205199
并发1--1579085205313---DefaultDispatcher-worker-3
并发2--1579085205313---DefaultDispatcher-worker-2
as1=1,as2=2
复制代码

观察上面demo的运行结果,是否是很舒服,看起来同步的方式内部倒是在异步操做。那上面注释中 挂起 是什么意思呢?并发

什么是挂起?

观察上面的打印日志,咱们不难发现,在调用 delay 函数时,线程并无停下,相对来讲,只是咱们的协程代码块被挂起,等待恢复。只有前面的挂起函数执行结束,咱们的协程代码块才能继续执行。借用一幅图来讲明以下:框架

img

因此所谓的挂起实际上是代码层次的一个处理,从而使得咱们能够以同步形式去写异步的代码。异步

非阻塞程序?

所谓的非阻塞,其实就是切换了线程,观察打印日志变化,咱们能够发现,当咱们直接 GlobalScope.launch 启动一个协程时,此时运行的线程为默认的线程,因此协程被称为非阻塞的实现方式。async


suspend关键字的做用

先看下面的图ide

image-20200115191719199

当使用suspend修饰后的函数咱们称其为挂起函数,那么挂起函数有什么做用?为何test 的suspend 标志是黑的?

继续看截图

image-20200115192201091

挂起函数为何只能在挂起函数中使用呢??

咱们再继续往下看:看一下java字节码

image-20200115193946330

这个 Continuation是什么呢?按照字面意思,意思为延续。那咱们该怎么理解呢?

通常来讲 Continuation 表明的是<剩余的计算的概念>,也就是 接下来要执行的代码。官方的解释叫作 挂起点

好比我有一段代码:

println("123".length)
复制代码

最早执行的是"123".length,而后执行 println打印长度,此时执行 "123".length 就能够当作一个挂起点,也就是代码从这里中止,等待计算出结果,然而此时内部线程却没有中止,当计算完的时候,也就是挂起结束,此时接着执行咱们的打印语句。

切换到咱们的suspend中,它表明的就是一个***标志*** 的做用,有suspend修饰的表明的函数叫作挂起函数,当编译器碰到这个标志的函数,就知道它是一个可能会耗时的操做。

挂起函数为何只能在挂起函数中使用呢?

image-20200115200403816

由于普通函数参数并无带 Continuation啊,至关于没有挂起点,编译器没法判断,因此此时会报错。

为何test 的suspend 标志是黑的?

编译器知道它是挂起函数,可是test内部没有挂起函数啊,因此此时编译器提示。

那这个函数就一点做用没有?

有做用,就是限制这个函数只能挂起函数调用。


在Android中使用

倒计时功能

class Main3Activity : AppCompatActivity() {
    private val mainScope = CoroutineScope(Dispatchers.Default)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main3)
        progressBar.max = 100
        mainScope.launch {
            (1..100).forEach {
                delay(100)
                withContext(Dispatchers.Main) {
                    progressBar.secondaryProgress = it
                }
            }
        }

    }
  
  onDestory(){
    //记得关闭
  }
  
}
复制代码

Jietu20200115-203101-HD


结合 ViewModel 使用

class MainViewModel : ViewModel() {
    fun test() {
        viewModelScope.launch {

        }
    }
}
复制代码

在ViewModel取消时,协程将自动关闭


结合 Lifecycle 使用

导入如下依赖

implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0-rc03"
复制代码

因而刚才的倒计时代码改成以下:

class Main3Activity : AppCompatActivity() {
  			....
        lifecycleScope.launch {
           ...
        }
    }
}
复制代码

一样,当fragment或者Activity关闭时,协程一样将自动关闭。

查看源码,会发现,viewModel中的 viewModelScope 和 Lifecycle lifecycleScope,实现方式一模一样:

image-20200115204534210

本篇,咱们没有过多的从源码上去追寻,协程究竟是什么,尽可能从语法,使用者的角度入手,带着你们从侧面去理解协程,但愿你们都能有本身的理解。

若是但愿深刻研究,推荐如下博客:

Beenyhuo

相关文章
相关标签/搜索