android流式布局实现sku,[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
android流式布局实现sku,[Kotlin协程] 回调地狱的一种解决思路相关推荐
- android kotlin 回调,[Kotlin协程] 回调地狱的一种解决思路
背景 异步回调的方式虽然实现了需求,但是牺牲了可读性,过多的回调让代码变得难以维护. 解决思路 rxjava->协程 Java语言开发的时候,可以借助一些第三方库如RxJava,来让减少嵌套. ...
- android 流失布局,GitHub - hongyangAndroid/FlowLayout: [不再维护]Android流式布局,支持单选、多选等,适合用于产品标签等。...
FlowLayout Android流式布局,支持单选.多选等,适合用于产品标签等. ##特色 以setAdapter形式注入数据 直接设置selector为background即可完成标签选则的切换 ...
- Android流式布局FlowLayout,一款针对Tag的布局
交流群 : 668524118 本群主要用于编程技术 ,及创意作品 ,思维架构的交流 ,欢迎喜欢创新 ,热爱生活的朋友加入 ! 前言 flow layout, 流式布局, 这个概念在移动端或者前端开发 ...
- android分组流式布局,Android 流式布局实现
概述 本文主要分享Android流式布局实现,实现效果如下: 在实现之前先来看一下View的生命周期,如下图: 流式布局属于自定义ViewGroup,重点关注onMeasure与onLayout方法 ...
- Android 流式布局
Android 流式布局 首先目标 最近Android流式布局很火爆,首先我们可以把这一标签页的整体看成一个容器,然后容器内有许多小控件(TextView,Button,ImageView等),再来这 ...
- android 自定义flowlayout,Android 流式布局FlowLayout 实现关键字标签
FlowLayout Android 流式布局FlowLayout 实现关键字标签 效果图 使用方法 在项目根目录的build.gradle文件中加入如下代码 maven { url "ht ...
- Android自定义组合布局,Android 流式布局 + 自定义组合控件
自定义组合控件 package yanjupeng.bawei.com.day09.two; import android.content.Context; import android.util.A ...
- Android流式布局的实现原理
1.流式布局的特点以及应用场景 特点:当上面一行的空间不够容纳新的TextView时候, 才开辟下一行的空间 原理图: 场景:主要用于关键词搜索或者热门标签等场景 2.自定义ViewGroup,重点重 ...
- android 仿快递步骤_【干货速递,建议收藏】Android 流式布局,一篇搞定
今天我们来看Android的流式布局. 所谓流式布局指的是ViewGroup中同一行的宽度不足以容纳下一个子view时,进行换行处理,而不需要考虑子view的大小,每一行的高度以其中最高者为准. Ta ...
- android 流式布局官方,Android 流式布局
FlowLayoutManager 这是一个自定义实现流式布局的LayoutManager,配合RecyclerView使用,可实现标签效果:目前的问题是没有实现View的缓存,以后再补吧. 代码示例 ...
最新文章
- ZABBIX企业微信新版告警
- c语言 free参数 指针,C语言之free函数以及野指针介绍
- mysql 执行计划详解_mysql explain执行计划详解
- 信息系统项目管理师-信息系统项目整体管理核心知识点思维脑图
- WindowsServer2012 R2 64位中文标准版(IIS8.5)下手动搭建PHP环境详细图文教程(二)安装IIS8.5...
- [Buzz Today]2012.08.08
- API:互联网是如何在幕后工作的?
- 独辟蹊径,Python打造新型基于图像隐写术的C2通道
- bzoj 1083: [SCOI2005]繁忙的都市
- 智能计米器jk76怎么安装_春节智能锁消费指南:只看价格的后果有多严重?
- python 谷歌翻译 api_调用谷歌翻译API
- AppCompat是什么?
- 西数绿盘的“C1门”!!!
- Cookie、Session和Token(学习笔记)
- 软件设计模式—命令模式
- cpe(通用平台枚举)命名规范及python CPE库实战
- NIST的安全内容自动化协议(SCAP)以及SCAP中文社区简介
- 微机原理与接口技术系列笔记(一)
- singleTask vs singleInstance
- HTML+CSS+JAVASCRIPT简介
热门文章
- mysql node 可视化_使用Prometheus进行Substrate节点可视化监控
- 拓端tecdat|Matlab马尔可夫链蒙特卡罗法(MCMC)估计随机波动率(SV,Stochastic Volatility) 模型
- 拓端tecdat|R语言机器学习实战之多项式回归
- chapter 9 series
- 清华大学操作系统OS学习(六)——进程和线程
- opencv+Dlib python大眼代码
- 基于感知哈希算法的图像相似匹配计算实战
- python实现arxiv论文数据解析处理
- 2021-08-01创建查询关键字及数据类型
- canny算子 轮廓闭合_python实现:prewitt, laplace,sobel,scharr, canny, hed