android kotlin 回调,[Kotlin协程] 回调地狱的一种解决思路
背景
异步回调的方式虽然实现了需求,但是牺牲了可读性,过多的回调让代码变得难以维护.
解决思路
rxjava->协程
Java语言开发的时候,可以借助一些第三方库如RxJava,来让减少嵌套. 但是实际落地的效果并不理想, 因为不能保证团队里面每个人都擅长并且能够接受Rx的风格.
在使用kotlin协程的时候我发现了新世界.
协程+流式设计
我的需求是实现一个订阅功能,并将功能模块化后提供给其他产品线.
外部调用
外部调用者传入一个id,sdk告诉外部购买成功还是发生异常.
内部实现
内部实现大体上是以上6步. 但是这里每一步都是异步的,如果用java实现,免不了处理很多回调代码.
我尝试使用kotlin+协程完成,发现出奇的简单易读.
// 偷懒 构造一个Activity的扩展方法,反正最后是以Activity的方式来提供出去
fun Activity.goSubscript(productID: String, exceptionHandler: CoroutineExceptionHandler) =
CoroutineScope(Dispatchers.Main).launch(exceptionHandler) {
SubscriptHelper(this@goSubscript).run {
// 1
init()
// 2
getAvailableHistory()?.let { purchase ->
if (checkPurchase(purchase)) {
return@launch;
}
}
// 3
val skuDetails = getAvailableProducte(productID)
// 4
val purchase = subscriptProducte(this@goSubscript, skuDetails)
// 5
val isCheckedSuccess = checkPurchase(purchase)
// 6
if (!isCheckedSuccess) {
val acknowSuccess = acknowledgePurchase(purchase)
logd(content = "客户端确认${if (acknowSuccess) "成功" else "失败"} ");
}
}
}
复制代码
体会了下kotlin的协程代码风格,这大概就是Kotlin的魅力吧. 那么怎么来实现上诉风格的代码呢?
这里大概需要有两个问题要解决:
怎么把Java异步回调转化成suspend函数.
怎么处理java回调哪些异常场景.
把回调转化成suspend函数
解决办法:利用通道
使用suspendCoroutine
// 1. 建立和GP/AppStore的连接
suspend fun init(): Boolean = try {
withTimeout(1500) {
suspendCoroutine { continuation ->
billingClient =
BillingClient.newBuilder(context).setListener(listenerUpdate)
.enablePendingPurchases()
.build()
.apply {
startConnection {
onBillingSetupFinishedFun {
continuation.resume(true)
}
}
};
}
}
} catch (e: TimeoutCancellationException) {
throw InitException()
}
复制代码
看上面这个初始化的栗子,先构造了一个withTimeout协程代码块,然后 在suspendCoroutine代码块会生成一个continuation参数,在onBillingSetupFinishedFun函数回调的时候,我们直接使用这个参数来发送消息,结束挂起.
例如成功的时候返回
continuation.resume(true)
复制代码
异常的时候可以
continuation.resumeWithException()
复制代码使用channel
有的情况下回调不是通过callback完成的,例如使用Handler机制完成的回调代码,怎么转化成协程.
var channel: Channel = Channel();
// 利用channel发送
var listenerUpdate: PurchasesUpdatedListener = object : PurchasesUpdatedListener {
override fun onPurchasesUpdated(
billingResult: BillingResult?,
purchases: MutableList?
) {
CoroutineScope(Dispatchers.Main).launch {
purchases?.let {
if (it.size >= 0) {
purchase = it[0]
}
}
channel.send(billingResult!!)
channel.close()
}
}
};
// 利用channel接收
suspend fun subscriptProducte(activity: Activity, skuDetails: SkuDetails): Purchase {
billingClient.launchBillingFlow(
activity,
BillingFlowParams.newBuilder().setSkuDetails(skuDetails).build()
)
val result = channel.receive()
when (result.responseCode) {
BillingClient.BillingResponseCode.OK -> {
return purchase!!
}
BillingClient.BillingResponseCode.USER_CANCELED -> {
throw UserCancleException()
}
else -> {
throw SubscriptProductException(result.debugMessage)
}
}
}
复制代码
也就是说channel可以单独出来作为一个对象使用.
协程异常处理
上面的调用函数设计的时候,我构造了一个参数exceptionHandler,用作整个事件的异常处理.
fun Activity.goSubscript(productID: String, exceptionHandler: CoroutineExceptionHandler) =
CoroutineScope(Dispatchers.Main).launch(exceptionHandler) {
复制代码
然后我定义了一些异常类型
class InitException(msg: String = "") : Exception()
class RepeateSubscription(msg: String = "") : Exception()
class NoProducteException(msg: String = "") : Exception()
class UserCancleException(msg: String = "") : Exception()
class SubscriptProductException(msg: String = "") : Exception()
class AcknowException(msg: String = "") : Exception()
复制代码
然后当内部出现购买失败的回调的时候,主动抛出一个异常,把整个事件流中断,外部处理这些异常也很简单,直接定义一个exceptionHandler(是个参数是throwable的函数)对象接收.
总结起来就是:
通过抛出异常来中断事件流
异常在协程内部会向上传导
外部开辟一个协程任务的时候,可以给内部指定一个异常处理器
总结
看过一些讲协程的文章,大多都是讲一些原理和API的使用,总感觉没有吸引到让我觉得他比线程模式更好,然后自己摸索着在项目中写了一次.
大概这就是 纸上得来终觉浅,绝知此事要躬行吧.
Android开发,为什么要用Kotlin而不是Java
关于找一找教程网
本站文章仅代表作者观点,不代表本站立场,所有文章非营利性免费分享。
本站提供了软件编程、网站开发技术、服务器运维、人工智能等等IT技术文章,希望广大程序员努力学习,让我们用科技改变世界。
[[Kotlin协程] 回调地狱的一种解决思路]http://www.zyiz.net/tech/detail-139988.html
android kotlin 回调,[Kotlin协程] 回调地狱的一种解决思路相关推荐
- 【Kotlin 协程】协程简介 ( 协程概念 | 协程作用 | 创建 Android 工程并进行协程相关配置开发 | 异步任务与协程对比 )
文章目录 一.协程概念 二.协程作用 三.创建 Android 工程并进行协程相关配置 1.创建 Android 工程 2.配置协程环境 3.布局文件 4.异步任务代码示例 5.协程代码示例 6.完整 ...
- 关于C10K、异步回调、协程、同步阻塞
2019独角兽企业重金招聘Python工程师标准>>> 最近到处在争论这些话题,发现很多人对一些基础的常识并不了解,在此发表一文做一下解释.此文未必能解答所有问题,各位能有一个大致的 ...
- 并发编程之进程池,线程池 和 异步回调,协程
1.进程池和线程池 2.异步回调 3.协程 4.基于TCP使用多线程实现高并发 一.进程池和线程池 什么是进程池和线程池: ''' 池 Pool 指的是一个容器 线程池就是用来存储线程对象的 容器创建 ...
- 同步与异步,回调与协程
目录 概念上下文: 同步的方式: 异步加回调的方式: 异步协程方式: 总结: 这里分享一个 协程原理到实现,全局分析丨协程的切换与调度视频点击查看:「链接」 正文 本文主要介绍在网络请求中的同步与异步 ...
- Unity 协程回调
按照顺序Debug,1-5进行 //按照1-5顺序 //---------------------------------------------------- StartCoroutine(func ...
- Android kotlin实战之协程suspend详解与使用
前言 Kotlin 是一门仅在标准库中提供最基本底层 API 以便各种其他库能够利用协程的语言.与许多其他具有类似功能的语言不同,async 与 await 在 Kotlin 中并不是关键字,甚至都不 ...
- Android使用suspendCancellableCoroutine将回调转换为协程
转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/122058124 本文出自[赵彦军的博客] 文章目录 suspendCancella ...
- go 协程回调函数 传入参数_ECMAScript 6 入门教程—Generator 函数的异步应用
作者 | 阮一峰异步编程对 JavaScript 语言太重要.JavaScript 语言的执行环境是"单线程"的,如果没有异步编程,根本没法用,非卡死不可.本章主要介绍 Gener ...
- Retrofit+kotlin Coroutines(协程)+mvvm(Jetpack架构组件)实现更简洁的网络请求
前言 使用kotlin协程也有一段时间了,给我最大的感受就是完全可以替代Rxjava了,并且写起来更加的简洁. 6月份Retrofit发布的2.6.0版本内部支持了kotlin协程中的挂起(suspe ...
最新文章
- Bug: CuteEditor与IE8不兼容
- 用电脑发短信_丢掉你的手机数据线吧!用这个软件轻松在任何设备互传文件
- 【Lucene4.8教程之四】分析
- docker-compose观察实时日志_大数据项目实战之在线教育(03实时需求) - 十一vs十一...
- c语言字符串文库总结,C语言程序设计入门:字符串函数
- 输出结果 配置_经典架构新玩法:用单端仪表放大器实现全差分输出
- QRCode二维码生成方案及其在带LOGO型二维码中的应用(2)
- 华邦电子2022年1月营收为新台币86.90亿元
- Java8函数式编程详解
- Android 获取联系人列表
- 《MYSQL必知必会》—2.MySQL简介
- git 创建和合并分支
- 高通SDX12:sar sensor AW9610x驱动移植
- intel cpu core/“酷睿”系列发展史,供组装机的朋友们参考
- java 拉勾网,拉钩网java笔试题分享
- 转 主流蓝牙BLE控制芯片详解(5):Dialog DA14580
- JAVA面试大全(持续更新中...)
- android 银联支付必须要nfc吗,手机没有NFC功能,可以使用银联云闪付功能吗?
- Kafka基于Zookeeper搭建高可用集群实战
- svn 合并分支 idea