I am new to Android/Kotlin, and I am making an app, which loads different data from network with Room cache, and decided to use "network bound resource" algorithm (NBR in short), which can be simplified to this:
inline fun <ResultType, RequestType> networkBoundResource(
crossinline query: () -> Flow<ResultType>,
crossinline fetch: suspend () -> RequestType,
crossinline saveFetchResult: suspend (RequestType) -> Unit,
crossinline shouldFetch: (ResultType) -> Boolean = { true }
) = flow {
val data = query().first()
val flow = if (shouldFetch(data)) {
emit(Resource.Loading(data))
try {
saveFetchResult(fetch())
query().map { Resource.Success(it) }
} catch (throwable: Throwable) {
query().map { Resource.Error(throwable, it) }
}
} else {
query().map { Resource.Success(it) }
}
emitAll(flow)
}
This is the exact sample from Coding in Flow, very simular to Google's Github Browser implementation with LiveData and many more samples I've seen. Resource class is a simple state+data holder like this:
sealed class Resource<out R> {
class Success<out T>(val data: T) : Resource<T>()
class Error<out T>(val exception: Throwable, val data: T? = null) : Resource<T>()
class Loading<out T>(val data: T? = null) : Resource<T>()
}
But after implementing this in my repository class I've found some problems I could not find solution anywhere:
How do I force refresh data? I've made a separate function which reuses
fetchandsaveFetchResultimplementations to put data from network into DB, but I need to refresh UI loading indicators from both NBR flow collector and from that suspend refresh function, because NBR will never re-emit loading state for me. It works, but feels bad.On error in NBR it is emitting flow which converts any of the DB updated values to
Resource.Error, even those coming after successful refresh, which leads to repeating the same error message in UI even everything was fine on refresh.When this NBR is reused by multiple use cases how do I protect from being fetched multiple times? Do I need a mutex lock for the whole function?