I'm using the following code in my Android app to load data from a remote source into a local database cache.
inline fun <ResultType, RequestType> networkBoundResource(
crossinline query: () -> Flow<ResultType>,
crossinline fetch: suspend () -> RequestType,
crossinline saveFetchResult: suspend (RequestType) -> Unit,
crossinline onFetchSuccess: () -> Unit = { },
crossinline onFetchFailed: (Throwable) -> Unit = { },
crossinline shouldFetch: (ResultType) -> Boolean = { true }
) = flow {
val data = query().first()
val flow = if (shouldFetch(data)) {
emit(Resource.(data))
try {
// this could take a while, I want to keep getting updates meanwhile
saveFetchResult(fetch())
onFetchSuccess()
query().map { Resource.Success(it) }
} catch (t: Throwable) {
onFetchFailed(t)
query().map { Resource.Error(t, it) }
}
} else {
query().map { Resource.Success(it) }
}
emitAll(flow)
}
The query is a database query that keeps emitting database updates through emitAll until we call this method again.
The problem with this setup is that Resource.Loading only contains a "snapshot" of the current data (first()) and we won't receive any database updates until we get to the end of the try/catch block and call emitAll. But I would like to keep receiving database updates while Loading is still in progress. However, I can't just call emitAll on Resource.Loading because it would block the whole Flow.
Is there a way to call emitAll on Loading and then switch to Success/Error once the try block has finished?