目标
首先,定义好异步结果泛化类型AsyncResult,此处会用到Kotlin泛型编程基础知识:
sealed class AsyncResult<out T : Any>
data class AsyncSuccess<out T : Any>(val data: T?) : AsyncResult<T>()
data class AsyncError(val error: String?) : AsyncResult<Nothing>()
inline fun <T : Any> AsyncResult<T>.onSuccess(action: (T?) -> Unit): AsyncResult<T> {
if (this is AsyncSuccess) action(data)
return this
}
inline fun <T : Any> AsyncResult<T>.onError(action: (String) -> Unit) {
if (this is AsyncError && error != null) action(error)
}
复制代码
基于此AsyncResult和Kotlin协程suspend关键字,可以定义任意异步操作(网络请求,数据库操作等)如下:
suspend fun demoAction(): AsyncResult<List<DemoItem>> {
//请暂时忽略实现方法
}
复制代码
接下来好戏登场,UI部分的代码:
launch {
demoAction()
.onSuccess {
Toast.makeText(this@MainActivity, "Successfully Fetched ${it?.size} Items", Toast.LENGTH_LONG)
.show()
}
.onError {
Toast.makeText(this@MainActivity, "Failed!! -- $it", Toast.LENGTH_LONG).show()
}
}
复制代码
非常优雅有木有?!
具体操作(实现)
展示过了魔术效果, 我们来揭秘下几处关键手法:
- sealed class 描述了受限的类继承结构,即限定了此类实例只能是有限的几种类型。 AsyncSuccess和AsyncError则是AsyncResult的派生类而已。
- onSuccess和oError是AsyncResult的扩展方法(Kotlin可以给已知的任何 class 类添加函数), 其中onSuccess还返回了自身对象,以便链式调用。
- onSuccess和onError均接受唯一一个Lambda参数, 从而可以实现形式上
onSuccess{}.onError{}
的写法。