kotlin: 用select选择“更快的结果”
一,代码:
例子:需要访问缓存和网络来获取数据,
如果从缓存先返回,先更新ui,从网络获取数据后再更新一次,
如果从网络先返回,更新ui
数据类:
data class Product(
//id
val productId: String,
//价格
val price: Double,
// 是不是缓存信息
val isCache: Boolean = false
)
调用:
//处理按钮点击事件
binding.button1.setOnClickListener {
runBlocking {
//从cache获取数据
suspend fun getCacheInfo(productId: String): Product? {
delay(300L)
return Product(productId, 9.9)
}
//从网络获取数据
suspend fun getNetworkInfo(productId: String): Product? {
delay(200L)
return Product(productId, 9.8)
}
//更新ui
fun updateUI(product: Product) {
println("${product.productId}==${product.price}")
}
val startTime = System.currentTimeMillis()
val productId = "xxxId"
// 1,缓存和网络,并发执行
val cacheDeferred = async { getCacheInfo(productId) }
val latestDeferred = async { getNetworkInfo(productId) }
// 2,在缓存和网络中间,选择最快的结果
val product = select<Product?> {
cacheDeferred.onAwait {
it?.copy(isCache = true)
}
latestDeferred.onAwait {
it?.copy(isCache = false)
}
}
// 3,更新UI
if (product != null) {
updateUI(product)
println("Time cost: ${System.currentTimeMillis() - startTime}")
}
// 4,如果当前结果是缓存,那么再取最新的网络服务结果
if (product != null) {
if (product.isCache) {
println("数据来自缓存");
val latest = latestDeferred.await()?: return@runBlocking
updateUI(latest)
println("Time cost: ${System.currentTimeMillis() - startTime}")
} else {
println("数据不是来自缓存");
}
}
}
}
cache的数据有可能出现问题返回变慢,
我们用 async 搭配 select 来使用。
async 可以实现并发,select 则可以选择最快的结果
代码中要注意的地方:
用 select 这个高阶函数包裹了两次查询的服务,同时传入了泛型参数 Product,代表我们要选择的数据类型是 Product。
用了 async 包裹了 getCacheInfo()、getNetworkInfo() 这两个挂起函数,这是为了让这两个查询实现并发执行。
用 onAwait{} 将执行结果传给了 select{},而 select 才能进一步将数据返回给 product 局部变量。
注意,这里我们用的 onAwait{},而不是 await()
二,测试效果:
cache用时100毫秒时
cache用时300毫秒时