Kotlin协程的使用

目录

引入kotlin协程

kotlin协程的三种启动方式

初识协程:

第一种启动方式(runBlocking:T)

第二种启动方式(launch:Job)

第三种启动方式(async/await:Deferred)

实现你的第一个Coroutine程序


浅析Kotlin协程 ——协程是什么?https://blog.csdn.net/qq_17798399/article/details/95234416

引入kotlin协程

在Android module中的build.gradle的dependencies中添加依赖。

 implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.1.1"

kotlin协程的三种启动方式

1.runBlocking:T     

2.launch:Job

3.async/await:Deferred

随后再详细介绍三种启动方式

 

初识协程:

首先我们来看一眼协程是什么样的, 以下引用了官网的一个例子:

fun main(args: Array<String>) {
    launch(CommonPool) {
        delay(1000L) 
        println("World!") 
    }
    println("Hello,")
    Thread.sleep(2000L)
}

/* 
运行结果: ("Hello,"会立即被打印, 1000毫秒之后, "World!"会被打印)
Hello, 
World!
*/

运行流程:

A. 主流程:

  1. 调用系统的launch方法启动了一个协程, 跟随的大括号可以看做是协程体.
    (其中的CommonPool暂且理解成线程池, 指定了协程在哪里运行)
  2. 打印出"Hello,"
  3. 主线程sleep两秒
    (这里的sleep只是保持进程存活, 目的是为了等待协程执行完)

B. 协程流程:

  1. 协程延时1秒
  2. 打印出"World!"

解释一下delay方法:
在协程里delay方法作用等同于线程里的sleep, 都是休息一段时间, 但不同的是delay不会阻塞当前线程, 而像是设置了一个闹钟, 在闹钟未响之前, 运行该协程的线程可以被安排做了别的事情, 当闹钟响起时, 协程就会恢复运行.

协程启动后还可以取消
launch方法有一个返回值, 类型是Job, Job有一个cancel方法, 调用cancel方法可以取消协程, 看一个数羊的例子:

fun main(args: Array<String>) {
    val job = launch(CommonPool) {
        var i = 1
        while(true) {
            println("$i little sheep")
            ++i
            delay(500L)  // 每半秒数一只, 一秒可以输两只
        }
    }

    Thread.sleep(1000L)  // 在主线程睡眠期间, 协程里已经数了两只羊
    job.cancel()  // 协程才数了两只羊, 就被取消了
    Thread.sleep(1000L)
    println("main process finished.")
}

运行结果是:

1 little sheep
2 little sheep
main process finished.

如果不调用cancel, 可以数到4只羊.

第一种启动方式(runBlocking:T)

runBlocking  方法用于启动一个协程任务,通常只用于启动最外层的协程,例如线程环境切换到协程环境。

runBlocking启动的协程任务会阻断当前线程,直到该协程执行结束。

 执行结果:可以清楚的看到先将协程中的任务完成才执行主线程中的逻辑

第二种启动方式(launch:Job)

我们最常用的用于启动协程的方式,它最终返回一个Job类型的对象,这个Job类型的对象实际上是一个接口,它包涵了许多我们常用的方法。例如join()启动一个协程、cancel() 取消一个协程

该方式启动的协程任务是不会阻塞线程的

执行结果:可以清楚的看到主线程没有被阻塞

 

第三种启动方式(async/await:Deferred)

1.async和await是两个函数,这两个函数在我们使用过程中一般都是成对出现的。

2.async用于启动一个异步的协程任务,await用于去得到协程任务结束时返回的结果,结果是通过一个Deferred对象返回的。

执行结果:可以看到当协程任务执行完毕时可以通过await()拿到返回结果 

实现你的第一个Coroutine程序

现在我们来开始编写我们的第一个Coroutine例子程序,这个程序的主要功能就是从手机媒体中加载一张图片,并把它显示在一个ImageView中。我们先来看看在未使用Coroutine之前使用同步的方式加载图片的代码如下:

val bitmap = MediaStore.Images.Media.getBitmap(contentResolver, uri)
imageView.setImageBitmap(bitmap)

在上边的代码中我们从媒体读取了一张图片并把它转化成Bitmap对象。因为这是一个IO操作,如果我们在UI主线程中调用这段代码,将可能导致程序卡顿或产生ANR崩溃,所以我们需要在新开的线程中调用下边的代码

val bitmap = MediaStore.Images.Media.getBitmap(contentResolver, uri)

接着我们需要在UI线程中调用下边的代码来显示加载的图片

imageView.setImageBitmap(bitmap)

为了实现这一功能在传统的android程序中我们需要使用Handler或AsyncTask将结果从非UI主线程发送到UI主线程进行显示,我们需要编写许多额外的代码。并且这些代码的可读性也不是十分的友好。下边我们来看看使用Kotlin的Coroutine来实现图片的加载的代码,如下:

val job = launch(Background) {
  val bitmap = MediaStore.Images.Media.getBitmap(contentResolver,uri) 
  launch(UI) {
    imageView.setImageBitmap(bitmap)
  }
}

我们先忽略返回值job,我们稍后会进行介绍,在这儿我们关心的事情是launch函数和参数Background与UI。与之前使用同步的方式加载图片相比唯一的不同就在于这儿我们调用了lauch函数。lauch()创建并启动了一个协程,这儿的参数Background是一个CoroutineContext对象,确保这个协程运行在一个后台线程,确保你的应用程序不会因耗时操作而阻塞和崩溃。你可以像下边这样定义一个CoroutineContext:

internal val Background = newFixedThreadPoolContext(2, "bg")

他将使用含有两个线程的线程池来执行协程里边的操作。在第一个协程里边我们又调用了launch(UI)创建并启动了一个新的协程,这儿的UI并不是我们自己创建的,他是Kotlin在Android平台里边预定义的一个CoroutineContext,代表着在UI主线程中执行协程里边的操作。所以我们将更新程序界面的操作imageView.setImageBitmap(bitmap)放在了这个协程里。通过这儿的例子代码你会发现在kotlin里边使用协程来实现线程间的通信和切换非常的简单,比RxJava还简单。看上去就跟你写同步的方式的代码一样。

取消协程

在上边的例子中我们返回了一个Job类型的对象job。通过调用job.cancel()我们能够取消一个协程。例如当我们退出当前Activity的时候,图片还没有加载完。这个时候我们就可以在onDestroy中调用job.cancel()来取消这个未完成的任务。这与我们使用Rxjava时调用dipose()或使用AsyncTask时调用cancel() 来取消未完成的操作的作用是一样的。

 参考文章:

https://www.jianshu.com/p/04f28bbc66dc

https://www.jianshu.com/p/9f720b9ccdea

https://www.jianshu.com/p/b6fb75cfaf5a

  • 14
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值