破解otlin协程ndroid篇腾讯云开发者社区

关键词:Kotlin 协程 Android Anko

Android 上面使用协程来替代回调或者 RxJava 实际上是一件非常轻松的事儿,我们甚至可以在更大的范围内结合 UI 的生命周期做控制协程的执行状态~

我们曾经提到过,如果在 Android 上做开发,那么我们需要引入

Anko 也提供了一些比较方便的方法,例如 onClick 等等,如果需要,也可以引入它的依赖:

简单来说:

协程的原理和用法我们已经探讨了很多了,关于 Android 上面的协程使用,我们就只给出几点实践的建议。

Android 开发经常想到的一点就是让发出去的请求能够在当前 UI 或者 Activity 退出或者销毁的时候能够自动取消,我们在用 RxJava 的时候也有过各种各样的方案来解决这个问题。

协程有一个很天然的特性能刚够支持这一点,那就是作用域。官方也提供了 MainScope 这个函数,我们具体看下它的使用方法:

我们发现它其实与其他的 CoroutineScope 用起来没什么不一样的地方,通过同一个叫 mainScope 的实例启动的协程,都会遵循它的作用域定义,那么 MainScope 的定义时怎样的呢?

如果我们在触发前面的操作之后立即在其他位置触发作用域的取消,那么该作用域内的协程将不再继续执行:

如果我们快速依次点击上面的两个按钮,结果就显而易见了:

尽管我们前面体验了 MainScope 发现它可以很方便的控制所有它范围内的协程的取消,以及能够无缝将异步任务切回主线程,这都是我们想要的特性,不过写法上还是不够美观。

官方推荐我们定义一个抽象的 Activity,例如:

这样在 Activity 退出的时候,对应的作用域就会被取消,所有在该 Activity 中发起的请求都会被取消掉。使用时,只需要继承这个抽象类即可:

除了在当前 Activity 内部获得 MainScope 的能力外,还可以将这个 Scope 实例传递给其他需要的模块,例如 Presenter 通常也需要与 Activity 保持同样的生命周期,因此必要时也可以将该作用域传递过去:

多数情况下, Presenter 的方法也会被 Activity 直接调用,因此也可以将 Presenter 的方法生命成 suspend 方法,然后用 coroutineScope 嵌套作用域,这样 MainScope 被取消后,嵌套的子作用域一样也会被取消,进而达到取消全部子协程的目的:

抽象类很多时候会打破我们的继承体系,这对于开发体验的伤害还是很大的,因此我们是不是可以考虑构造一个接口,只要 Activity 实现这个接口就可以拥有作用域以及自动取消的能力呢?

首先我们定义一个接口:

我们有一个朴实的愿望就是希望实现这个接口就可以自动获得作用域,不过问题来了,这个 scope 成员要怎么实现呢?留给接口实现方的话显然不是很理想,自己实现吧,又碍于自己是个接口,因此我们只能这样处理:

接下来的事情就是在合适的实际去创建和取消对应的作用域了,我们接着定义两个方法:

因为我们需要 Activity 去实现这个接口,因此直接强转即可,当然如果考虑健壮性,可以做一些异常处理,这里作为示例仅提供核心实现。

剩下的就是在 Application 里面注册一下这个监听了,这个大家都会,我就不给出代码了。

我们看下如何使用:

我们也可以增加一些有用的方法来简化这个操作:

这样在 Activity 当中还可以这样写:

注意,示例当中用到了 IdentityHashMap,这表明对于 scope 的读写是非线程安全的,因此不要在其他线程试图去获取它的值,除非你引入第三方或者自己实现一个 IdentityConcurrentHashMap,即便如此,从设计上 scope也不太应该在其他线程访问。

我们之前做例子经常使用 GlobalScope,但 GlobalScope 不会继承外部作用域,因此大家使用时一定要注意,如果在使用了绑定生命周期的 MainScope 之后,内部再使用 GlobalScope 启动协程,意味着 MainScope 就不会起到应有的作用。

这里需要小心的是如果使用了一些没有依赖作用域的构造器,那么一定要小心。例如 Anko 当中的 onClick扩展:

也许我们也就是图个方便,毕竟 onClick 写起来可比 setOnClickListener 要少很多字符,同时名称上看也更加有事件机制的味道,但隐藏的风险就是通过 onClick 启动的协程并不会随着 Activity 的销毁而被取消,其中的风险需要自己思考清楚。

当然,Anko 会这么做的根本原因在于 OnClickListener 根本拿不到有生命周期加持的作用域。不用 GlobalScope 就无法启动协程,怎么办?结合我们前面给出的例子,其实这个事儿完全有别的解法:

我们在前面定义的 MainScoped 接口中,可以通过 scope 拿到有生命周期加持的 MainScope 实例,那么直接用它启动协程来运行 OnClickListener 问题不就解决了嘛。所以这里的关键点在于如何拿到作用域。

这样的 listener 我已经为大家在框架中定义好啦,请参见 2.3。

当然除了直接使用一个合适的作用域来启动协程之外,我们还有别的办法来确保协程及时被取消。

大家一定用过 RxJava,也一定知道用 RxJava 发了个任务,任务还没结束页面就被关闭了,如果任务迟迟不回来,页面就会被泄露;如果任务后面回来了,执行回调更新 UI 的时候也会大概率空指针。

考虑到前面提到的 Anko 扩展 onClick 无法取消协程的问题,我们也可以搞一个 onClickAutoDisposable。

我们知道 launch 会启动一个 Job,因此我们可以通过 asAutoDisposable 来将其转换成支持自动取消的类型:

那么 AutoDisposableJob 的实现只要参考 AutoDisposable 的实现依样画葫芦就好了 :

这样的话,我们就可以使用这个扩展了:

当 button 这个对象从 window 上撤下来的时候,我们的协程就会收到 cancel 的指令,尽管这种情况下协程的执行不会跟随 Activity 的 onDestroy 而取消,但它与 View 的点击事件紧密结合,即便 Activity 没有被销毁, View 本身被移除时也会直接将监听中的协程取消掉。

如果大家想要用这个扩展,我已经帮大家放到 jcenter 啦,直接使用:

在 Android 上使用协程,更多的就是简化异步逻辑的写法,使用场景更多与 RxJava 类似。在使用 RxJava 的时候,我就发现有不少开发者仅仅用到了它的切线程的功能,而且由于本身 RxJava 切线程 API 简单易用,还会造成很多无脑线程切换的操作,这样实际上是不好的。那么使用协程就更要注意这个问题了,因为协程切换线程的方式被 RxJava 更简洁,更透明,本来这是好事情,就怕被滥用。

这一篇文章,主要是基于我们前面讲了的理论知识,进一步往 Android 的具体实战角度迁移,相比其他类型的应用,Android 作为 UI 程序最大的特点就是异步要协调好 UI 的生命周期,协程也不例外。一旦我们把协程的作用域规则以及协程与 UI 生命周期的关系熟稔于心,那么相信大家使用协程时一定会得心应手的。

THE END
0.构造动力体制与复合造山作用摘要: 构造动力体制是研究区域大地构造演化和成矿地质环境的基础,而造山带作为全球金属矿产资源集中产出的地带,同时保留了地球地质构造演化最为丰富的记录,因而是用来解剖不同构造动力体制及相关成矿环境和成矿作用的主要对象。板块构造源于大洋,描述和解释的是以水平运动为主导的板块构造导致的大陆边缘增生和大洋板块消jvzquC41jvsm0{mj|0tfv8~uzd532:82627/j}r
1.纬向构造体系纬向构造体系,又称东西复杂构造带。1926年李四光在《地球表面形象之主因》一文中叙述了纬向构造存在的原因。1929年把它概括为东西构造带,并按它们所在的纬度在东亚地区划分出五个带。纬向构造体系 其主体是由东西走向的强烈挤压带,东西走向的褶皱和挤压性的断裂带构成。jvzquC41dcolg7xqiq{/exr1ngsnc8XjqyOopnwNkpq/j}rAngsncRi?88849?64
2.海湾煤矿三号井开拓巷道施工组织设计通用设计设计说明(四)、地质构造带施工 地质构造带施工时,顶板破碎,压力较大,必须采用砌碹支护、锚网喷、锚网喷和锚索联合支护,冒顶时用金属拱架支护,在地质构造带施工时,必须采取前探支护。 1、砌碹支护厚度为300mm,料石规格为300×300×150mm,一般用在伪板、直接顶破碎且较薄而老顶不会离层时支护。 jvzquC41yy}/otfs0qxh1qyon1813:4271671@<8::4tj}rn
3.完整mes代码(含客户端和server端4)构造带有集群策略的 clusterinvoker 经过上述操作,已经拿到了 server 端 Invokers,放入了 directory 的 cacheinvokers 数组里面缓存。后续的操作对应本文从 url 到 invoker 的过程的最后一步,由 directory 生成带有特性集群策略的 invoker。 //(四)new cluster injvzquC41dnuh0lxfp0tfv8|gkzooa<>838<988ftvkimg8igvcomu86333;72=<
4.安全生产考试题库带答案(通用13套)引导语:保护劳动者的生命安全和职业健康是安全生产最根本、最深刻的内涵,是安全生产本质的核心。以下是小编为大家带来的安全生产考试题库带答案,希望能帮助到大家。 安全生产考试题库带答案 1 一、单选(每题2分,每题只有一个正确答案) 1、我国安全生产的方针是什么(B) jvzquC41yy}/qq6220ipo8pcqunj1yjkzwt06=<5984ivvq
5.济南金穗实业有限公司1.工作原理及构造 带式压滤脱水机是由上下两条张紧的滤带夹带着污泥层,从一连串按规律排列的辘 压筒中呈S形弯曲经过,靠滤带本身的张力形成对污泥层的压榨力和剪切力,把污泥层中的毛细水挤压出来,获得含固量较高的泥饼,从而实现污泥脱水,如图6所示。带式压滤脱水机有很多形式,但一般都分成以下四个工作区: jvzq<84yyy4tfsslu0ipo8sgyuewkn|0cuv@kmB35