美文网首页
Androdi kotlin Coroutines(协程)详解

Androdi kotlin Coroutines(协程)详解

作者: 水天滑稽天照八野滑稽石 | 来源:发表于2020-09-15 01:09 被阅读0次

    Androdi kotlin Coroutines(协程)详解 (一)
    Androdi kotlin Coroutines(协程)详解 (二)
    Androdi kotlin Coroutines(协程)详解 (三)
    Androdi kotlin Coroutines(协程)详解 (四)
    Androdi kotlin Coroutines(协程)详解 (五)
    Androdi kotlin Coroutines(协程)详解 (六)

    二、协程的启动

    build.gradle 引入协程库

    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7" //协程核心库
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7" //Android协程扩展库
    

    2.1 启动方法

    2.1.1 GlobalScope启动
    GlobalScope.launch {
      //to do some thing
    }
    

    GlobalScope 实现了接口 CoroutineScope ,而 CoroutineScope 有 launch 方法,不阻塞线程
    相关的源码如下:

    public fun CoroutineScope.launch(
        context: CoroutineContext = EmptyCoroutineContext,
        start: CoroutineStart = CoroutineStart.DEFAULT,
        block: suspend CoroutineScope.() -> Unit
    ): Job {
        val newContext = newCoroutineContext(context)
        val coroutine = if (start.isLazy)
              LazyStandaloneCoroutine(newContext, block) 
            else
              StandaloneCoroutine(newContext, active = true)
        coroutine.start(start, coroutine, block)
        return coroutine
    }
    

    比如下面的代码:

        fun startCoroutineByGlobeScope() {
            println("start execute ${Thread.currentThread().name}")
            GlobalScope.launch {
                println("launch start execute ${Thread.currentThread().name}")
                delay(1000)
                println("launch end execute ${Thread.currentThread().name}")
            }
            println("end execute ${Thread.currentThread().name}")
            Thread.sleep(2000)
        }
    

    运行结果:

    start execute main
    end execute main
    launch start execute DefaultDispatcher-worker-1 @coroutine#1
    launch end execute DefaultDispatcher-worker-1 @coroutine#1
    

    Job

    后台的工作。从概念上讲,作业是一种可取消的东西,它的生命周期最终将完成。Job 可以取消并且有简单生命周期,它有三种状态:

    State [isActive] [isCompleted] [isCancelled]
    New (optional initial state) false false false
    Active (default initial state) true false false
    Completing (optional transient state) true false false
    Cancelling (optional transient state) false false true
    Cancelled (final state) false true true
    Completed (final state) false true false
    //Job中的方法
    job.isActive //是否存活
    job.isCancelled //是否关闭
    job.isCompleted //是否完成
    job.cancel() //关闭
    job.join() //挂起协程直到执行完毕
    job.start() //开始执行
    
    2.1.2 CoroutineScope启动
    CoroutineScope(context = EmptyCoroutineContext).launch {
      // to do something
    }
    
    2.1.3 runBlocking {}启动

    runBlocking {}是创建一个新的协程同时阻塞当前线程,直到协程结束。这个不应该在协程中使用,主要是为main函数和测试设计的。

    private fun runBlockingCoroutine() {
      println("runBlockingCoroutine start work thread ${Thread.currentThread().name}")
            runBlocking {
                delay(1000)
                println("runBlockingCoroutine ${Thread.currentThread().name}")
            }
      println("runBlocking end work thread ${Thread.currentThread().name}")
    }
    
    2.1.4 实现CoroutineScope接口,初始化上下文

    如GlobalScope 是 CoroutineScope 的一个单例实现


    2.2 四种启动方式 CoroutineStart

    public enum class CoroutineStart {
      DEFAULT,
      LAZY,
      @ExperimentalCoroutinesApi
      ATOMIC,
      @ExperimentalCoroutinesApi
      UNDISPATCHED;
    }
    
    模式 功能
    DEFAULT 立即执行协程体
    LAZY 懒汉式,只有在需要的情况下运行
    ATOMIC 立即执行协程体,但在开始运行之前无法取消,实验api
    UNDISPATCHED 立即在当前线程执行协程体,直到第一个 suspend 调用,实验api
    2.2.1 DEFAULT

    DEFAULT 是饿汉式启动, launch 调用后,会立即进入待调度状态,一旦调度器 OK 就可以开始执行。
    示例:

      Log.d(TAG, " oncreate start")
      GlobalScope.launch(start = CoroutineStart.DEFAULT) {
      Log.d(TAG, "block start")
      for (i in 1..5) {
        Log.d(TAG, "num is $i")
        delay(500)
      }
      Log.d(TAG, "block end")
    }
    Log.d(TAG, " oncreate end")
    

    运行结果:

    D/TestActivity: oncreate start
    D/TestActivity: oncreate end
    D/TestActivity: block start
    D/TestActivity: num is 1
    D/TestActivity: num is 2
    D/TestActivity: num is 3
    D/TestActivity: num is 4
    D/TestActivity: num is 5
    D/TestActivity: block end
    
    2.2.2 LAZY

    LAZY 是懒汉式启动, launch 后并不会有任何调度行为,协程体也自然不会进入执行状态,直到我们需要它执行的时候。这其实就有点儿费解了,什么叫我们需要它执行的时候呢?就是需要它的运行结果的时候, launch 调用后会返回一个 Job 实例,对于这种情况,我们可以:

    • 调用 Job.start ,主动触发协程的调度执行
    • 调用 Job.join ,隐式的触发协程的调度执行
      Log.d(TAG, " oncreate start")
      val job = GlobalScope.launch(start = CoroutineStart.LAZY) {
      Log.d(TAG, "block start")
      for (i in 1..5) {
          Log.d(TAG, "num is $i")
          delay(500)
       }
       Log.d(TAG, "block end")
      }
      job.start()
      Log.d(TAG, " oncreate end")
    
    2.2.3 ATOMIC

    ATOMIC 只有涉及 cancel 的时候才有意义,在这里我们就简单认为 cancel 后协程会被取消掉,也就是不再执行了。那么调用cancel 的时机不同,结果也是有差异的,例如协程调度之前、开始调度但尚未执行、已经开始执行、执行完毕等等。

      Log.d(TAG, " oncreate start")
      val job = GlobalScope.launch(start = CoroutineStart.ATOMIC) {
      Log.d(TAG, "block start")
      for (i in 1..5) {
        Log.d(TAG, "num is $i")
        delay(500)
      }
      Log.d(TAG, "block end")
      }
      job.cancel()
      Log.d(TAG, " oncreate end")
    
    2.2.4 UNDISPATCHED

    协程在这种模式下会直接开始在当前线程下执行,直到第一个挂起点,这听起来有点儿像前面的 ATOMIC ,不同之处在于UNDISPATCHED 不经过任何调度器即开始执行协程体。当然遇到挂起点之后的执行就取决于挂起点本身的逻辑以及上下文当中的调度器了。

            Log.d(TAG, " oncreate start")
            val job = GlobalScope.launch(start = CoroutineStart.UNDISPATCHED) {
                Log.d(TAG, "block start")
                for (i in 1..5) {
                    Log.d(TAG, "num is $i")
                    delay(500)
                }
                Log.d(TAG, "block end")
            }
            Log.d(TAG, " oncreate job.start")
            job.start()
            Log.d(TAG, " oncreate end")
    

    相关文章

      网友评论

          本文标题:Androdi kotlin Coroutines(协程)详解

          本文链接:https://www.haomeiwen.com/subject/lekxyktx.html