1.官方文档地址

github.com/Kotlin/kotl…

2. 协程的配置

compile "org.jetbrains.kotlinx:kotlinx-coroutines-android:0.18"

3.开启协程

Coroutines are experimental feature in Kotlin. You need to enable coroutines in Kotlin compiler by adding the following line to gradle.properties file。
协程是Kotlin一项实验性的功能,你需要打开在项目工程 gradle.properties中声明打开。

添加代码: kotin.coroutines = enable

4. 在UIContext启动协程,可以更新UI

import kotlinx.coroutines.experimental.CommonPool  // 运行在线程池中一个协程
import kotlinx.coroutines.experimental.Unconfined // 在当前默认的协程中运行
import kotlinx.coroutines.experimental.android.UI //运行在可控制UI的协程中...launch(UI) { // launch coroutine in UI contextfor (i in 10 downTo 1) { // countdown from 10 to 1 hello.text = "Countdown $i ..." // update textdelay(500) // wait half a second}hello.text = "Done!"}
复制代码

5. 取消一个协程任务

We can keep a reference to the Job object that launch function returns and use it to cancel coroutine when we want to stop it.

我们能持有协程的引用,通过它去获取协程处理后的结果或取消协程

    val job = launch(UI) { // launch coroutine in UI contextfor (i in 10 downTo 1) { // countdown from 10 to 1 hello.text = "Countdown $i ..." // update textdelay(500) // wait half a second}hello.text = "Done!"}// cancel coroutine on clickjob.cancel()
}
复制代码

6. 在UI线程中使用actor

1. 模式一: At most one concurrent job(最多执行一次)

使用情况:View防止被多次点击,造成没必要的浪费。

fun View.onClick(action: suspend () -> Unit) {// launch one actorval eventActor = actor<Unit>(UI) {for (event in channel) action()}// install a listener to activate this actorsetOnClickListener { eventActor.offer(Unit)}
}
复制代码

官方解释:

Try clicking repeatedly on a circle in this version of the code. The clicks are just ignored while the countdown animation is running. This happens because the actor is busy with an animation and does not receive from its channel. By default, an actor's mailbox is backed by RendezvousChannel, whose offer operation succeeds only when the receive is active.

在上面的这份代码中,进行循环的点击,当一次点击的倒计时动画进行时,后续频繁点击事件将会被忽略。原因是因为此actor正在忙于处理该动画,并且将receive状态设置为unactive,当有actor.offer()时,由于此actor的receive状态为unactive,所以事件就会被抛弃!

模式二: Event conflation(事件地合并)

Sometimes it is more appropriate to process the most recent event, instead of just ignoring events while we were busy processing the previous one. The actor coroutine builder accepts an optional capacity parameter that controls the implementation of the channel that this actor is using for its mailbox. The description of all the available choices is given in documentation of the Channel() factory function.use ConflatedChannel by passing Channel.CONFLATED capacity value.

当我们正在执行一次点击的动画时,后续频繁点击事件更合理的处理方式是接受在动画结束期间的最后一次点击事件,而不是像上面那样直接被忽视。actor协程在创建时,可接受一个参数来控制它内部的channel(也称为信箱)的实现方式。通过传递参数Channel.CONFLATED来创建一个ConflatedChannel(channel的一种实现类型)

fun Node.onClick(action: suspend (MouseEvent) -> Unit) {// launch one actor to handle all events on this nodeval eventActor = actor<MouseEvent>(UI, capacity = Channel.CONFLATED) { // <--- Changed herefor (event in channel) action(event) // pass event to action}// install a listener to offer events to this actoronMouseClicked = EventHandler { event ->eventActor.offer(event)}
}
复制代码

Now, if a circle is clicked while the animation is running, it restarts animation after the end of it. Just once. Repeated clicks while the animation is running are conflated and only the most recent event gets to be processed.

当一次动画没有结束,在这期间的点击事件都将被合并成一次,当动画结束后,又会仅此一次的启动该动画!

模式三:Sequence Event(串行事件)

You can experiment with capacity parameter in the above line to see how it affects the behaviour of the code. Setting capacity = Channel.UNLIMITED creates a coroutine with LinkedListChannel mailbox that buffers all events. In this case, the animation runs as many times as the circle is clicked.

上面我们看到了通过actor来创建协程,参数capacity来控制channel(信箱)的类型。你能够尝试capacity的不同值来体验它带来的效果。比如,我们设置capacity=Channel.UNLIMITED 来创建一个内部的channel(信箱)类型为LinkedListChannel,顾名思义它能接受我们的每一次事件。在这样的情景下,我们点击按钮多少次,动画将会执行多少次!

模式四: more type(通过修改capacity的类型,创建不同的channel)

7. Blocking operation(块级操作)

官方给出的事例:

fun fib(x: Int): Int =if (x <= 1) 1 else fib(x - 1) + fib(x - 2)fun setup(hello: Text, fab: Circle) {var result = "none" // the last result// counting animation launch(UI) {var counter = 0while (true) {hello.text = "${++counter}: $result"delay(100) // update the text every 100ms}}// compute the next fibonacci number of each clickvar x = 1fab.onClick {result = "fib($x) = ${fib(x)}"x++}
}复制代码

Issume(产生问题): Try clicking on the circle in this example. After around 30-40th click our naive computation is going to become quite slow and you would immediately see how the UI thread freezes, because the animation stops running during UI freeze.

根据上面的代码,如果我们快速点击30-40次,计算就会变得越来越慢,UI线程慢慢被冻结,动画也就会停止运行。

Solusation(解决方案): Blocking Operation(块级操作) The fix for the blocking operations on the UI thread is quite straightforward with coroutines. We'll convert our "blocking" fib function to a non-blocking suspending function that runs the computation in the background thread by using run function to change its execution context to CommonPool of background threads. Notice, that fib function is now marked with suspend modifier. It does not block the coroutine that it is invoked from anymore, but suspends its execution when the computation in the background thread is working

在协程中通过块级操作直接来处理UI,我们可以使用“run”函数来改变它的执行上下文到一个后台线程(CommonPool),从而将一个阻塞的“fib”函数转化为一个不被阻塞的挂起函数。注意,此时的“fib”函数被suspend修饰,这个函数使用时不会阻塞协程,当后台线程计算时,它会挂起此函数的执行,如下:

suspend fun fib(x: Int): Int = run(CommonPool) {if (x <= 1) 1 else fib(x - 1) + fib(x - 2)
}
复制代码

Note(说明):You can run this code and verify that UI is not frozen while large Fibonacci numbers are being computed. However, this code computes fib somewhat slower, because every recursive call to fib goes via run. This is not a big problem in practice, because run is smart enough to check that the coroutine is already running in the required context and avoids overhead of dispatching coroutine to a different thread again. It is an overhead nonetheless, which is visible on this primitive code that does nothing else, but only adds integers in between invocations to run. For some more substantial code, the overhead of an extra run invocation is not going to be significant.

你能运行这份代码,验证在计算大数字时,Ui线程会不会阻塞。然而,它计算fib时会变得更慢,因为每一次回调fib函数时都会运行run方法,但是它并不是一个大问题,因为run函数是非常智能的,它会检查当前管理并正在运行的协程,避免此协程在不同的线程中重复的运行。尽管原始代码中在协程中反复的使用,但是不造成什么影响,因为每一个协程持有的是这份代码的Int值,对于一些更实质性的代码,额外运行调用的开销并不显著。

为了不反复的调用run函数,当然你也可以这样:

suspend fun fib(x: Int): Int = run(CommonPool) {fibBlocking(x)
}fun fibBlocking(x: Int): Int = if (x <= 1) 1 else fibBlocking(x - 1) + fibBlocking(x - 2)
复制代码

8. Lifecycle and coroutine parent-child hierarchy(生命周期绑定与父子继承关系)

(Issume: )A typical UI application has a number of elements with a lifecycle. Windows, UI controls, activities, views, fragments and other visual elements are created and destroyed. A long-running coroutine, performing some IO or a background computation, can retain references to the corresponding UI elements for longer than it is needed, preventing garbage collection of the whole trees of UI objects that were already destroyed and will not be displayed anymore.

(问题)传统的UI应用都会包含大量拥有生命周期的元素,如窗口,界面,控件... 当这个元素不在需要的时候,协程可能存在它的引用,为了解决这个问题。

(solution)The natural solution to this problem is to associate a Job object with each UI object that has a lifecycle and create all the coroutines in the context of this job.

(解决办法:)将协程与每一个控件元素的生命周期绑定。

interface JobHolder {val job: Job
}
复制代码
class MainActivity : AppCompatActivity(), JobHolder {override val job: Job = Job() // the instance of a Job for this activityoverride fun onDestroy() {super.onDestroy()job.cancel() // cancel the job when activity is destroyed}// the rest of code
}
复制代码
val View.contextJob: Jobget() = (context as? JobHolder)?.job ?: NonCancellable
复制代码

这样的话,每一个控件都与该控件所在的Activity中的Job关联起来了,使用如下:

fun View.onClick(action: suspend () -> Unit) {// launch one actor as a parent of the context jobval eventActor = actor<Unit>(contextJob + UI, capacity = Channel.CONFLATED) {for (event in channel) action()}// install a listener to activate this actorsetOnClickListener {eventActor.offer(Unit)}
}
复制代码
官方解释

Notice how contextJob + UI expression is used to start an actor in the above code. It defines a coroutine context for our new actor that includes the job and the UI dispatcher. The coroutine that is started by this actor(contextJob + UI) expression is going to become a child of the job of the corresponding context. When the activity is destroyed and its job is cancelled all its children coroutines are cancelled, too.

它包含两个上下文contextJob + UI来创建一个协程actor对象,该协程将会成为contextJob的子类,当Activity被销毁,contextJob会被取消,那么它的子类协程都将会被取消。

9.Starting coroutine in UI event handlers without dispatch(在协程中不使用调度器)

使用调度器的情况:(默认使用)
fun setup(hello: Text, fab: Circle) {fab.onMouseClicked = EventHandler {println("Before launch")launch(UI) { println("Inside coroutine")delay(100)println("After delay")} println("After launch")}
}Before launch
After launch
Inside coroutine
After delay复制代码

However, in this particular case when coroutine is started from an event handler and there is no other code around it, this extra dispatch does indeed add an extra overhead without bringing any additional value. In this case an optional CoroutineStart parameter to launch, async and actor coroutine builders can be used for performance optimization. Setting it to the value of CoroutineStart.UNDISPATCHED has the effect of starting to execute coroutine immediately until its first suspension point as the following example shows:

在上述案例中,只有等EventHandler把事情处理完毕后,才开始协程,这种额外的调度确实增加了额外的开销而没有带来任何附加价值。我们可以通过参数CoroutineStart来控制,此参数受用与launch、async、actor。设置 CoroutineStart.UNDISPATCHED 将马上开始协程,知道遇到挂载点为止。代码如下:

fun setup(hello: Text, fab: Circle) {fab.onMouseClicked = EventHandler {println("Before launch")launch(UI, CoroutineStart.UNDISPATCHED) { // <--- Notice this changeprintln("Inside coroutine")delay(100)                            // <--- And this is where coroutine suspends      println("After delay")}println("After launch")}
}Before launch
Inside coroutine
After launch
After delay复制代码

Kotlin(android)协程中文翻译相关推荐

  1. Kotlin高级协程

    Kotlin高级协程 一.前言 二.先从线程说起 三.协程的设计思想 四.协程特点:优雅的实现移步任务 五.协程基本使用 六.协程和线程相比有什么特点,如何优雅的实现异步任务 一.前言 在文章正式上干 ...

  2. 【对比Java学Kotlin】协程简史

    文章目录 一.概念释义 1.1 协程定义 1.2 与线程的关系 1.3 协程简史 二.种类划分 2.1 按调用栈分类 2.2 按调度方式分类 三.异步编程 3.1 多线程 3.2 回调 3.3 Pro ...

  3. 十一、kotlin的协程(一)

    theme: Chinese-red 学习的前提 java线程需要大概知道点 协程是线程执行的任务, 协程和用户线程的区别在于, 协程背靠强大的编译器, 协程有专属于协程的调度器和一堆方便好用的函数, ...

  4. Kotlin中协程理解与实战(一)

    Kotlin中协程理解与实战(一) 什么是协程 在Android中协程用来解决什么问题 协程是: suspend -也称为挂起或暂停,用于暂停执行当前协程,并保存所有局部变量: resume -用于让 ...

  5. kotlin coroutines 协程教程-入门用法

    kotlin coroutines 协程教程-入门用法 Coroutine 协程,是kotlin 上的一个轻量级的线程库,对比 java 的 Executor,主要有以下特点: 更轻量级的 api 实 ...

  6. Kotlin 之 协程

    初识协程,启动取消协程,Flow异步流,协程并发 目录 (一)初识协程 协程是什么? Android中协程解决了什么问题? 协程的挂起与恢复 挂起和阻塞 协程的调度器 Dispatchers 任务泄露 ...

  7. Kotlin的协程与生命周期

    文章目录 一.前言 二.引入依赖 三.代码示例 1.基础用法 2.repeatOnLifecycle 3.flowWithLifecycle 4.lifecycle.whenCreated.lifec ...

  8. Kotlin(3)-协程和操作符重载,Java程序员秋招三面蚂蚁金服

    Kotlin 文件和类不存在一对一关系 共生体 继承 修饰符 空指针问题 正文 重难点 协程 想了很久,关于协程的内容,在官网上确实有很多内容,基础知识概念,基本使用,以及 流操作,通道,异常处理,并 ...

  9. 十一、kotlin的协程 - 缓存、volatile、内存屏障和cas(四) --- 跑题篇

    本章写着写着就跑题了, 又不舍得删除, 新手看 # 协程的共享变量安全问题简单入门和## volatile 不保证原子性部分代码, 其他可以不看, 太乱, 也没用 协程的共享变量安全问题简单入门 在使 ...

最新文章

  1. Java基础--通过反射获取成员方法并使用
  2. 浅谈数据结构-平衡二叉树
  3. inotifywait监听php,利用inotifywait监控主机文件和目录
  4. 关于SAP Commerce product API对description字段的处理
  5. 贪心(数据结构):COGS 468. [NOI2010]超级钢琴
  6. .Net4.0 Parallel编程(三)Data Parallelism下
  7. Web MIDI API W3C
  8. 为什么两个controller的session的id不一样_新笑傲江湖手游服务器名字为什么不一样解答...
  9. ES6数组的扩展~超详细、超好理解哦
  10. 如何打开oracle的回闪,oracle回闪操作
  11. git reset HEAD 用法
  12. 拼多多根据ID取商品详情 API 返回值说明
  13. 『重磅』免费无限量下载知网/万方/维普等数据库文献的正规渠道
  14. 在 TortoiseGit 中使用 stash 操作---暂存操作、部分提交
  15. 售价2999元起  华为5G自拍视频旗舰nova7系列强势来袭
  16. 【千寻位置前端校招笔试、一面、二面】
  17. Kubernetes权威指南
  18. 猴子都能看懂的噪声(noise)专题
  19. 联想c245如何使用html,[转载]联想C245一体机电脑改XP成功,REALTEK ALC269声卡正常驱动...
  20. 酷安(coolapk.apk) 10.0简介

热门文章

  1. mockito无效_Mockito模拟无效方法
  2. Python – numpy.linspace()
  3. C++基础之布尔类型,什么是C++的布尔类型
  4. 开课吧Java课堂:是什么TreeMap类
  5. docker配置深度学习环境
  6. 查看aix下安装并升级的C/C++ compiler 的版本
  7. Lua中调用C/C++函数 (转)
  8. (转载)构建public APIs与CORS
  9. [Unity] Unity3D研究院编辑器之自定义默认资源的Inspector面板
  10. C# Winform添加全局快捷键(老板键)