欲善其事,必利其器的问题在于
很多时候并不知道什么器才是好的器
这两天用协程改造老旧代码,效果还是很显著的,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等,挺香的。
总结
一种将异步代码当同步代码写的 语法糖
本站广告由 Google AdSense 提供
0条评论