美文网首页
Kotlin之协程(二)

Kotlin之协程(二)

作者: 有没有口罩给我一个 | 来源:发表于2019-03-15 13:56 被阅读0次

上一篇写协程的概念,这节将介绍协程的一些细节

先来看看相关的几个类或接口

//协程域
public interface CoroutineScope {
      //这个协程域的上下文
    public val coroutineContext: CoroutineContext
}

这个协程域中中包含了协程上下文,即这个域中存在一个,CoroutineContext:

async(Dispatchers.IO) {
      coroutineContext.plus()// 可以操作上下文plus加法操作符
        log(" "Show data in UI"")
    }

Dispatchers.IO也是一个CoroutineContext

CoroutineScope by MainScope() 委托MainScope实现CoroutineScope 的上下文:

  public fun MainScope(): CoroutineScope = ContextScope(SupervisorJob() + Dispatchers.Main)

线程调度(Dispatchers and threads)

private fun asyncShowData() = launch {
    launch { // context of the parent, main runBlocking coroutine,默认受父协程上下文的限制,阻塞父协程
        log("main runBlocking      : I'm working in thread ${Thread.currentThread().name}")
    }
    launch(Dispatchers.Unconfined) { // not confined -- will work with main thread,没有任何限制,将在main线程运行
        log("Unconfined            : I'm working in thread ${Thread.currentThread().name}")
    }
    launch(Dispatchers.Default) { // will get dispatched to DefaultDispatcher,在DefaultDispatcher线程中运行
        log("Default               : I'm working in thread ${Thread.currentThread().name}")
    }
    launch(newSingleThreadContext("MyOwnThread")) { // will get its own new thread,在自定义线程中运行
        log("newSingleThreadContext: I'm working in thread ${Thread.currentThread().name}")
    }
}

打印日志:

[main]: Unconfined            : I'm working in thread main
[DefaultDispatcher-worker-1]: Default               : I'm working in thread     DefaultDispatcher-worker-1
 [MyOwnThread]: newSingleThreadContext: I'm working in thread MyOwnThread
 [main]: main runBlocking      : I'm working in thread main

没有受限制和受限制的协程(Unconfined vs confined dispatcher)

private fun asyncShowData() = launch {
    launch(Dispatchers.Unconfined) { // not confined -- will work with main thread
        log("Unconfined      : I'm working in thread ${Thread.currentThread().name}")
        delay(500)
        log("Unconfined      : After delay in thread ${Thread.currentThread().name}")
    }
    launch { // context of the parent, main runBlocking coroutine
        log("main runBlocking: I'm working in thread ${Thread.currentThread().name}")
        delay(1000)
        log("main runBlocking: After delay in thread ${Thread.currentThread().name}")
    }
}

日志

 Unconfined      : I'm working in thread main
 [main]: main runBlocking: I'm working in thread main
 [kotlinx.coroutines.DefaultExecutor]: Unconfined      : After delay in thread kotlinx.coroutines.DefaultExecutor
 [main]: main runBlocking: After delay in thread main

当没有受限制的线程在delay后,后面程序将运行在kotlinx.coroutines.DefaultExecutor,默认是调度线程池中;

切换上下文(Jumping between threads)

private fun asyncShowData() = launch {
    newSingleThreadContext("Ctx1").use { ctx1 ->
        newSingleThreadContext("Ctx2").use { ctx2 ->
            runBlocking(ctx1) {
                log("Started in ctx1")
                withContext(ctx2) {
                    log("Working in ctx2")
                }
                log("Back to ctx1")
            }
        }
    }
}

日志

 [Ctx1]: Started in ctx1
 [Ctx2]: Working in ctx2
 [Ctx1]: Back to ctx1

CoroutineContext 的Job(Job in the context)

 private fun asyncShowData() = launch {
    log("My job is ${coroutineContext[Job]}")
}

日志

[main]: My job is StandaloneCoroutine{Active}@2b26878e

父协程和子协程(Children of a coroutine)

/**
    * 取消父协程,会把所有的子协程给取消
 */
private fun asyncShowData() = launch {
    val request = launch {
        
        //不受request协程的影响
        GlobalScope.launch {
            log("job1: I run in GlobalScope and execute independently!")
            delay(1000)
            log("job1: I am not affected by cancellation of the request")
        }
        
        //该协程的上下文默认使用request的上下文,受request的影响,所以改协程是request的子协程
        launch {
            delay(100)
            log("job2: I am a child of the request coroutine")
            delay(1000)
            log("job2: I will not execute this line if my parent request is cancelled")
        }
    }
    delay(500)
    request.cancel() // 取消request协程
    delay(1000)
    log("main: Who has survived request cancellation?")
}

日志

[DefaultDispatcher-worker-1]: job1: I run in GlobalScope and execute independently!
[main]: job2: I am a child of the request coroutine
[DefaultDispatcher-worker-1]: job1: I am not affected by cancellation of the request
[main]: main: Who has survived request cancellation?

使用join等待所有的子协程完成

 private fun asyncShowData() = launch {
    log("parent start")
    val job = launch {
        log("1child start")
        launch {
            log("2child start")
            delay(8000)
            log("2child complete")
        }
        delay(5000)
        log("1child complete")
    }
    job.join()
    log("parent end")
}

日志

  [main]: cancel
  [main]: parent start
  [main]: 1child start
  [main]: 2child start
  [main]: 1child complete
  [main]: 2child complete
  [main]: parent end

结合上下文元素(Combining context elements)

 val newJob = Job()
    val job = launch(Dispatchers.Default + newJob) {
        log("start")
        delay(5000)
        log("I'm working in thread ${Thread.currentThread().name}")
    }
    log("${newJob == job}  ${newJob}    ${job}")
    newJob.cancel()

可以看到newJob也可以操作该协程的状态

下一篇文章将是使用协程尝试构建MVP

文档

相关文章

网友评论

      本文标题:Kotlin之协程(二)

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