不管做什么事情,我们都要有一颗上进的心,写代码也是如此。最开始要写得出,然后要写得对,然后要写得又对又好,最后再追求那个传说中的快。
当然,现在好用又强大的三方库越来越多了,业务开发渐渐的变成 api boy
了。当然,api boy
亦有差距,就看你能不能把 api
封装得足够好用了。
今天,我来教教你们如何用协程包装下微信分享的接口。
首先看看微信分享接口,它的发送数据接口和接收接口是分开的。
发送请求为:
fun shareToWx(msg: WXMediaMessage, transaction: String){ val req = SendMessageToWX.Req() // 唯一标示一个请求, 用于微信返回的回调使用 req.transaction = transaction // 调用 api 接口,发送数据到微信 api.sendReq(req) }
然后跳转到微信,微信处理完后,会调起 WXEntryActivity
,通过 onResp
去接收消息:
class WXEntryActivity() : AppCompatActivity(), IWXAPIEventHandler{ override fun onResp(baseResp: BaseResp) { // 通过 baseResp.transaction 去 match 请求 // TODO handle the baseResp finish() } }
整个流程清晰,就是请求和回应分离了,虽然有 transaction
去追踪请求连,但我也见过完全不用这个参数的开发,而是做了个假设:短时间必定只有一次分享,而且回应应该也很快,所以从微信收到的结果必定是当前界面分享的。。。(反正一般跑起来都是正常的。)
更多高明的开发可能就会用上 EventBus
了,把 resp
抛到 EventBus
里,然后业务自己去监听 EventBus
里的消息,然后处理。
这样也不是不可以,但总归一条业务链下来,代码要写在两个地方,维护起来也不是很爽,而且每次还要去关注那个 transaction
参数。
那该怎么包装呢?RxJava
有 RxJava
的包装,协程有协程的包装,但大体思路应该一样。
总之我们要善于利用新的工具去让这个世界变得更美好。对于我,我当然是选择更现代的协程了。
代码如下:
private val wxMsgChannelMap = HashMap<String, Channel<BaseResp>>() // 入口方法 suspend fun shareToWx(msg: WXMediaMessage): BaseResp { val req = SendMessageToWX.Req() // 构造唯一标示,仅内部使用 req.transaction = System.currentTimeMillis().toString() // 构建一个缓存一个结果的 channel val channel = Channel<BaseResp>(1) return withContext(Dispatchers.Main) { // 将 channel 存储起来 wxMsgChannelMap[transaction] = channel try { // 调用 api 接口,发送数据到微信 api.sendReq(req) // 协程等待 channel 的结果 channel.receive() } finally { channel.close() wxMsgChannelMap.remove(transaction) } } } class WXEntryActivity() : AppCompatActivity(), IWXAPIEventHandler{ override fun onResp(baseResp: BaseResp) { AppScope.launch(Dispatchers.Main) { // 从 map 中寻找到对应的 channel val channel = wxMsgChannelMap[baseResp.transaction] ?: return@launch if (channel.isClosedForSend || channel.isClosedForReceive) { return@launch } // 向 channel 发送数据 channel.send(baseResp) } finish() } }
上面的代码,其实很简单,就是借助了 channel
而已,但只要有这一层封装,业务放就可以将逻辑写得简洁明了了:
val msg = WXMediaMessage(...) // 构造消息 val result = shareToWx(msg) // 处理结果
是不是看上去就清爽多了?那可不可以做得更好呢? 我们必须要在工程中的特定目录下新建 WXEntryActivity
, 然后各个 app 里面的代码都是非常雷同,所以,我们能不能搞个库,把它给封装并隐藏起来?就可以造福更多的开发?WXEntryActivity
要求特定目录,那是不是只能动态生成? ksp
是不是就可以上场装逼了?
问:那继续搞下去吗?
答:不搞,现在的又不是不能用。