LiveData with Coroutines and Flow
我们经常在viewModel 中做些数据的操作:
1. 如果是one short 数据,我们可以这样使用:
val currentWeather: LiveData<String> = dataSource.fetchWeather()
2. 如果是flow数据,我们可以这样使用:
val currentWeatherFlow: LiveData<String> = dataSource.fetchWeatherFlow().asLiveData()
3. 如是是1+N的one short 数据:
val currentWeather: LiveData<String> = liveData {
emit(LOADING_STRING)
emitSource(dataSource.fetchWeather())
}
4. 如是是1+N的flow 数据:
val currentWeatherFlow: LiveData<String> =
dataSource.fetchWeatherFlow()
.onStart { emit(LOADING_STRING) }
.asLiveData()
5. one short 数据+switchMap:
val currentWeatherLiveData: LiveData<String> =
dataSource.fetchWeather().switchMap {
liveData { emit(heavyTransformation(it)) }
}
6. flow 数据+map:
val currentWeatherFlow: LiveData<String> =
dataSource.fetchWeatherFlow()
.map { heavyTransformation(it) }
.asLiveData()
也就是说:如果你是flow数据,那么推荐用flow api
val currentWeatherFlow: Flow<String> =
dataSource.fetchWeatherFlow()
.map { ... }
.filter { ... }
.dropWhile { ... }
.combine { ... }
.flowOn(Dispatchers.IO)
.onCompletion { ... }
7. 如果有些库如Retrofit, Room已经支持suspend 函数了, 那么你可以直接调用如下:
suspend fun doOneShot(param: String) : String{
return retrofitClient.doSomething(param)
}
@POST("/api/....")
suspend fun doSomething(
@Body map: @JvmSuppressWildcards Map<String, String>
): String
8. 如果一些第三方库没有支持suspend方法,只有回调的话,
可以用suspendCancellableCoroutine或是suspendCoroutine
suspend fun doOneShot(param: String) : Result<String> =
suspendCancellableCoroutine { continuation ->
api.addOnCompleteListener { result ->
continuation.resume(result)
}.addOnFailureListener { error ->
continuation.resumeWithException(error)
}.fetchSomething(param)
}
9.如果你需要flow数据,采用flow 构建
fun fetchWeatherFlow(): Flow<String> = flow {
var counter = 0
while(true) {
counter++
delay(2000)
emit(weatherConditions[counter % weatherConditions.size])
}
}
10. 如果要把Callback转化为flow ,采用callbackflow 构建
fun flowFrom(api: CallbackBasedApi): Flow<T> = callbackFlow {
val callback = object : Callback {
override fun onNextValue(value: T) {
offer(value)
}
override fun onApiError(cause: Throwable) {
close(cause)
}
override fun onCompleted() = close()
}
api.register(callback)
awaitClose { api.unregister(callback) }
}