背景

异步回调的方式虽然实现了需求,但是牺牲了可读性,过多的回调让代码变得难以维护.

解决思路

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协程] 回调地狱的一种解决思路相关推荐

  1. android kotlin 回调,[Kotlin协程] 回调地狱的一种解决思路

    背景 异步回调的方式虽然实现了需求,但是牺牲了可读性,过多的回调让代码变得难以维护. 解决思路 rxjava->协程 Java语言开发的时候,可以借助一些第三方库如RxJava,来让减少嵌套. ...

  2. android 流失布局,GitHub - hongyangAndroid/FlowLayout: [不再维护]Android流式布局,支持单选、多选等,适合用于产品标签等。...

    FlowLayout Android流式布局,支持单选.多选等,适合用于产品标签等. ##特色 以setAdapter形式注入数据 直接设置selector为background即可完成标签选则的切换 ...

  3. Android流式布局FlowLayout,一款针对Tag的布局

    交流群 : 668524118 本群主要用于编程技术 ,及创意作品 ,思维架构的交流 ,欢迎喜欢创新 ,热爱生活的朋友加入 ! 前言 flow layout, 流式布局, 这个概念在移动端或者前端开发 ...

  4. android分组流式布局,Android 流式布局实现

    概述 本文主要分享Android流式布局实现,实现效果如下: 在实现之前先来看一下View的生命周期,如下图: 流式布局属于自定义ViewGroup,重点关注onMeasure与onLayout方法 ...

  5. Android 流式布局

    Android 流式布局 首先目标 最近Android流式布局很火爆,首先我们可以把这一标签页的整体看成一个容器,然后容器内有许多小控件(TextView,Button,ImageView等),再来这 ...

  6. android 自定义flowlayout,Android 流式布局FlowLayout 实现关键字标签

    FlowLayout Android 流式布局FlowLayout 实现关键字标签 效果图 使用方法 在项目根目录的build.gradle文件中加入如下代码 maven { url "ht ...

  7. Android自定义组合布局,Android 流式布局 + 自定义组合控件

    自定义组合控件 package yanjupeng.bawei.com.day09.two; import android.content.Context; import android.util.A ...

  8. Android流式布局的实现原理

    1.流式布局的特点以及应用场景 特点:当上面一行的空间不够容纳新的TextView时候, 才开辟下一行的空间 原理图: 场景:主要用于关键词搜索或者热门标签等场景 2.自定义ViewGroup,重点重 ...

  9. android 仿快递步骤_【干货速递,建议收藏】Android 流式布局,一篇搞定

    今天我们来看Android的流式布局. 所谓流式布局指的是ViewGroup中同一行的宽度不足以容纳下一个子view时,进行换行处理,而不需要考虑子view的大小,每一行的高度以其中最高者为准. Ta ...

  10. android 流式布局官方,Android 流式布局

    FlowLayoutManager 这是一个自定义实现流式布局的LayoutManager,配合RecyclerView使用,可实现标签效果:目前的问题是没有实现View的缓存,以后再补吧. 代码示例 ...

最新文章

  1. ZABBIX企业微信新版告警
  2. c语言 free参数 指针,C语言之free函数以及野指针介绍
  3. mysql 执行计划详解_mysql explain执行计划详解
  4. 信息系统项目管理师-信息系统项目整体管理核心知识点思维脑图
  5. WindowsServer2012 R2 64位中文标准版(IIS8.5)下手动搭建PHP环境详细图文教程(二)安装IIS8.5...
  6. [Buzz Today]2012.08.08
  7. API:互联网是如何在幕后工作的?
  8. 独辟蹊径,Python打造新型基于图像隐写术的C2通道
  9. bzoj 1083: [SCOI2005]繁忙的都市
  10. 智能计米器jk76怎么安装_春节智能锁消费指南:只看价格的后果有多严重?
  11. python 谷歌翻译 api_调用谷歌翻译API
  12. AppCompat是什么?
  13. 西数绿盘的“C1门”!!!
  14. Cookie、Session和Token(学习笔记)
  15. 软件设计模式—命令模式
  16. cpe(通用平台枚举)命名规范及python CPE库实战
  17. NIST的安全内容自动化协议(SCAP)以及SCAP中文社区简介
  18. 微机原理与接口技术系列笔记(一)
  19. singleTask vs singleInstance
  20. HTML+CSS+JAVASCRIPT简介

热门文章

  1. mysql node 可视化_使用Prometheus进行Substrate节点可视化监控
  2. 拓端tecdat|Matlab马尔可夫链蒙特卡罗法(MCMC)估计随机波动率(SV,Stochastic Volatility) 模型
  3. 拓端tecdat|R语言机器学习实战之多项式回归
  4. chapter 9 series
  5. 清华大学操作系统OS学习(六)——进程和线程
  6. opencv+Dlib python大眼代码
  7. 基于感知哈希算法的图像相似匹配计算实战
  8. python实现arxiv论文数据解析处理
  9. 2021-08-01创建查询关键字及数据类型
  10. canny算子 轮廓闭合_python实现:prewitt, laplace,sobel,scharr, canny, hed