Kotlin Coroutine初探(一)

Kotlin Coroutine初探(一)

2017年,Google 宣布Kotlin 成为 Android 的官方开发语言,并在1.1版本加入了对 Coroutine(协程,可以简单看作是轻量级线程)的支持。

Coroutine是一种并发设计模式,在 Android 平台上使用它可以简化异步执行的代码。下面就让我们一起使用Coroutine进行编码吧!

启动协程

协程任务的构建需要通过Coroutine Builder来实现。

    /**
     * @param context 默认所创建的 Coroutine 会自动继承当前 Coroutine 的 context,如果有额外的 context 需要传递给所创建的 Coroutine 则可以通过第一个参数来设置
     * @param start 配置协程的启动模式,包含 DEFAULT、LAZY、ATOMIC和UNDISPATCHED四种模式
     * @param block 需要执行的方法
     *
     * @return 返回生成的协程任务对象Job
     * */
    fun CoroutineScope.launch(
            context: CoroutineContext = EmptyCoroutineContext,
            start: CoroutineStart = CoroutineStart.DEFAULT,
            block: suspend CoroutineScope.() -> Unit
    ): Job 

默认的Dispatchers

构建协程时,使用Dispatchers中定义的类型来实现。

    fun testDispatchers() {
        try {
            val defaultJob = GlobalScope.launch(context = Dispatchers.Default) { // 在后台启动一个新的协程并继续
                Log.e("ViewModel", "start--defaultJob:${Thread.currentThread().name};${Thread.currentThread().id};${coroutineContext[Job]}")
                withContext(context = Dispatchers.IO) {
                    Log.e("ViewModel", "launch--defaultJob:${Thread.currentThread().name};${Thread.currentThread().id};${coroutineContext[Job]}")
                }
                Log.e("ViewModel", "after--defaultJob:${Thread.currentThread().name};${Thread.currentThread().id};${coroutineContext[Job]}")
            }

            val mainJob = GlobalScope.launch(context = Dispatchers.Main) { // 在后台启动一个新的协程并继续
                Log.e("ViewModel", "start--mainJob:${Thread.currentThread().name};${Thread.currentThread().id};${coroutineContext[Job]}")
                withContext(context = Dispatchers.IO) {
                    Log.e("ViewModel", "launch--mainJob:${Thread.currentThread().name};${Thread.currentThread().id};${coroutineContext[Job]}")
                }
                Log.e("ViewModel", "after--mainJob:${Thread.currentThread().name};${Thread.currentThread().id};${coroutineContext[Job]}")
            }

            val unconfinedJob = GlobalScope.launch(context = Dispatchers.Unconfined) { // 在后台启动一个新的协程并继续
                Log.e("ViewModel", "start--unconfinedJob:${Thread.currentThread().name};${Thread.currentThread().id};${coroutineContext[Job]}")
                withContext(context = Dispatchers.IO) {
                    Log.e("ViewModel", "launch--unconfinedJob:${Thread.currentThread().name};${Thread.currentThread().id};${coroutineContext[Job]}")
                }
                Log.e("ViewModel", "after--unconfinedJob:${Thread.currentThread().name};${Thread.currentThread().id};${coroutineContext[Job]}")
            }

            val ioJob = GlobalScope.launch(context = Dispatchers.IO) { // 在后台启动一个新的协程并继续
                Log.e("ViewModel", "start--ioJob:${Thread.currentThread().name};${Thread.currentThread().id};${coroutineContext[Job]}")
                withContext(context = Dispatchers.IO) {
                    Log.e("ViewModel", "launch--ioJob:${Thread.currentThread().name};${Thread.currentThread().id};${coroutineContext[Job]}")
                }
                Log.e("ViewModel", "after--ioJob:${Thread.currentThread().name};${Thread.currentThread().id};${coroutineContext[Job]}")
            }
        } catch (e: Exception) {
            println(e.localizedMessage)
        }
    }

输出:

  • Dispatchers.Default,执行任务时,使用默认的协程线程池,线程个数为CPU个数 但不能少于2个。
    dispatchers_defalut
  • Dispatchers.Main,执行任务时,使用Android默认的UI线程。
    dispatchers_main
  • Dispatchers.Unconfined,执行任务时,使用当前线程。
    dispatchers_unconfined
  • Dispatchers.IO,执行任务时,使用默认的IO线程池,线程个数为Math.max(64,CPU个数)
    dispatch_io

默认的CoroutineStart

构建协程时,使用CoroutineStart中定义的类型来实现。

    fun testCoroutineStart() {
        try {
            val defaultJob = GlobalScope.launch(start = CoroutineStart.DEFAULT) { // 在后台启动一个新的协程并继续
                Log.e("ViewModel", "start--defaultJob:${Thread.currentThread().name};${Thread.currentThread().id};${coroutineContext[Job]}")
                withContext(context = Dispatchers.IO) {
                    Log.e("ViewModel", "launch--defaultJob:${Thread.currentThread().name};${Thread.currentThread().id};${coroutineContext[Job]}")
                }
                Log.e("ViewModel", "after--defaultJob:${Thread.currentThread().name};${Thread.currentThread().id};${coroutineContext[Job]}")
            }

            val lazyJob = GlobalScope.launch(start = CoroutineStart.LAZY) { // 在后台启动一个新的协程并继续
                Log.e("ViewModel", "start--lazyJob:${Thread.currentThread().name};${Thread.currentThread().id};${coroutineContext[Job]}")
                withContext(context = Dispatchers.IO) {
                    Log.e("ViewModel", "launch--lazyJob:${Thread.currentThread().name};${Thread.currentThread().id};${coroutineContext[Job]}")
                }
                Log.e("ViewModel", "after--lazyJob:${Thread.currentThread().name};${Thread.currentThread().id};${coroutineContext[Job]}")
            }
            lazyJob.start()

            val atomicJob = GlobalScope.launch(start = CoroutineStart.ATOMIC) { // 在后台启动一个新的协程并继续
                Log.e("ViewModel", "start--atomicJob:${Thread.currentThread().name};${Thread.currentThread().id};${coroutineContext[Job]}")
                withContext(context = Dispatchers.IO) {
                    Log.e("ViewModel", "launch--atomicJob:${Thread.currentThread().name};${Thread.currentThread().id};${coroutineContext[Job]}")
                }
                Log.e("ViewModel", "after--atomicJob:${Thread.currentThread().name};${Thread.currentThread().id};${coroutineContext[Job]}")
            }
            atomicJob.cancel()

            val undispatchedJob = GlobalScope.launch(start = CoroutineStart.UNDISPATCHED) { // 在后台启动一个新的协程并继续
                Log.e("ViewModel", "start--undispatchedJob:${Thread.currentThread().name};${Thread.currentThread().id};${coroutineContext[Job]}")
                withContext(context = Dispatchers.IO) {
                    Log.e("ViewModel", "launch--undispatchedJob:${Thread.currentThread().name};${Thread.currentThread().id};${coroutineContext[Job]}")
                }
                Log.e("ViewModel", "after--undispatchedJob:${Thread.currentThread().name};${Thread.currentThread().id};${coroutineContext[Job]}")
            }
        } catch (e: Exception) {
            println(e.localizedMessage)
        }
    }

输出:

  • CoroutineStart.DEFAULT,默认的启动模式,会直接开始执行任务,不需要单独调用job.start()
    coroutine_start_default
  • CoroutineStart.LAZY,懒加载模式,只有在调用了job.start()才会开始执行协程任务。
    coroutine_start_lazy
  • CoroutineStart.ATOMIC,原子模式,会直接开始执行任务,但取消任务时,如果任务还没开始执行,会取消不了任务。
    coroutine_start_atomic
  • CoroutineStart.UNDISPATCHED,不调度模式,会直接开始执行任务,但切换协程被挂起(切换线程)之后,再次resume时不会切换到之前启动的线程,而是以当前执行的线程去继续执行任务 。
    coroutine_start_undispatched

取消协程

协程构建之后,会返回Job对象,可以用来取消协程。

Job.cancel(cause: Throwable? = null): Boolean

抛出指定的异常来取消协程,如果传递空则抛出CancellationException

    fun testCancelCoroutine() {
        try {
            Log.e("ViewModel", "testCancelCoroutine")
            val defaultCancelJob = GlobalScope.launch { // 在后台启动一个新的协程并继续
                Log.e("ViewModel", "start--defaultCancelJob:${Thread.currentThread().name};${Thread.currentThread().id};${coroutineContext[Job]}")
                withContext(context = Dispatchers.IO) {
                    delay(10000)//延时10s
                    Log.e("ViewModel", "launch--defaultCancelJob:${Thread.currentThread().name};${Thread.currentThread().id};${coroutineContext[Job]}")
                }
                Log.e("ViewModel", "after--defaultCancelJob:${Thread.currentThread().name};${Thread.currentThread().id};${coroutineContext[Job]}")
            }
            defaultCancelJob.cancel()

        } catch (e: Exception) {
            e.printStackTrace()
        }

    }

输出:
coroutine_cancel

Job.cancelAndJoin()

等到协程任务被执行完成,才会取消。

    fun testCancelAndJoinCoroutine() {
        try {
            Log.e("ViewModel", "testCancelAndJoinCoroutine")
            val defaultCancelAndJoinJob = GlobalScope.launch { // 在后台启动一个新的协程并继续
                Log.e("ViewModel", "start--defaultCancelAndJoinJob:${Thread.currentThread().name};${Thread.currentThread().id};${coroutineContext[Job]}")
                withContext(context = Dispatchers.IO) {
                    delay(10000)//延时10s
                    Log.e("ViewModel", "launch--defaultCancelAndJoinJob:${Thread.currentThread().name};${Thread.currentThread().id};${coroutineContext[Job]}")
                }
                Log.e("ViewModel", "after--defaultCancelAndJoinJob:${Thread.currentThread().name};${Thread.currentThread().id};${coroutineContext[Job]}")
            }
            launch {
                defaultCancelAndJoinJob.cancelAndJoin()
                Log.e("ViewModel", "cancelAndJoin")
            }

        } catch (e: Exception) {
            e.printStackTrace()
        }

    }

输出:
coroutine_cancel_and_join

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值