欲善其事,必利其器的问题在于
很多时候并不知道什么器才是好的器
这两天用协程改造老旧代码,效果还是很显著的,git更改情况2000行大概是这样:
当然后面删得更多了,之前项目使用的是promise,但是这个promise for kotlin已经很久没更新了,大概是歪果仁追求新很早就用得了协程,用不着再造轮子了。
需求
整理下了需求,大概就是,需要能接收异常,需要在启动时能指定线程,希望有一个总是被执行的alwaysUI块,能简化的处理UI与IO的切换那么这样:
定义一个类文件,将以下代码作为顶级函数:
fun CoroutineScope.launchWithExceptionCatch(context: CoroutineContext = EmptyCoroutineContext, exceptionBlock: ((throwable: Throwable) -> Unit)? = null, alwaysUi: (() -> Unit)? = null, block: suspend CoroutineScope.() -> Unit) { launch(context + CoroutineExceptionHandler { coroutineContext, throwable -> //主要是alwaysUi异常记录 Log.e(TAG, "parent block context:${coroutineContext} exception:$throwable") }) { try { //协程代码块 默认主线程 block() } catch (e: Exception) { //防止因为生命周期导致的退出影响异常处理逻辑 if (e is CancellationException) return@launch Log.e(TAG, "sub block exception:$e") //协程代码块异常处理 exceptionBlock?.invoke(e) } //alwaysUi处理 withUI { alwaysUi?.invoke() } } } suspend fun <T> withUI(block: suspend CoroutineScope.() -> T): T { return withContext(Dispatchers.Main, block) } suspend fun <T> withIO(block: suspend CoroutineScope.() -> T): T { return withContext(Dispatchers.IO, block) }
那么,用的时候:
lifecycleScope.launchWithExceptionCatch(Dispatchers.IO, exceptionBlock = { throwable ->
//有点东西抛出了
}, alwaysUi = {
//按钮被禁用了 无论成功失败都得重新启用
}) {
//目前启动的时候已经是IO了 切个UI?
val res = withUI {
// 显示个弹窗?返回个数据?
"hello"
}
//做点耗时
delay(3000)
//显示一下
withUI { toastShort(res) }
}
或者:
lifecycleScope.launchWithExceptionCatch(exceptionBlock = { throwable -> //有点东西抛出了 }, alwaysUi = { //按钮被禁用了 无论成功失败都得重新启用 }) { //目前启动的时候啥都没指定 切个IO? val res = withIO { //做点耗时 返回个数据? delay(3000) "hello" } //显示一下 withUI { toastShort(res) } }
在kotlin这个协程里,还可以做点事儿,比如官方封好的withTimeOut、async …
以及一些特殊场景下使用的suspendCoroutine,flow等,挺香的。
总结
一种将异步代码当同步代码写的 语法糖
本站由以下主机服务商提供服务支持:
0条评论