¿Tiene alguna idea de cómo implementar un patrón de repositorio con las rutinas NetworkBoundResource y Kotlin? Sé que podemos lanzar una corutina dentro de un GlobalScope, pero puede conducir a una fuga de rutina. Me gustaría pasar un viewModelScope como parámetro, pero es un poco complicado cuando se trata de implementación (porque mi repositorio no conoce un CoroutineScope de ningún ViewModel).
abstract class NetworkBoundResource<ResultType, RequestType>
@MainThread constructor(
private val coroutineScope: CoroutineScope
) {
private val result = MediatorLiveData<Resource<ResultType>>()
init {
result.value = Resource.loading(null)
@Suppress("LeakingThis")
val dbSource = loadFromDb()
result.addSource(dbSource) { data ->
result.removeSource(dbSource)
if (shouldFetch(data)) {
fetchFromNetwork(dbSource)
} else {
result.addSource(dbSource) { newData ->
setValue(Resource.success(newData))
}
}
}
}
@MainThread
private fun setValue(newValue: Resource<ResultType>) {
if (result.value != newValue) {
result.value = newValue
}
}
private fun fetchFromNetwork(dbSource: LiveData<ResultType>) {
val apiResponse = createCall()
result.addSource(dbSource) { newData ->
setValue(Resource.loading(newData))
}
result.addSource(apiResponse) { response ->
result.removeSource(apiResponse)
result.removeSource(dbSource)
when (response) {
is ApiSuccessResponse -> {
coroutineScope.launch(Dispatchers.IO) {
saveCallResult(processResponse(response))
withContext(Dispatchers.Main) {
result.addSource(loadFromDb()) { newData ->
setValue(Resource.success(newData))
}
}
}
}
is ApiEmptyResponse -> {
coroutineScope.launch(Dispatchers.Main) {
result.addSource(loadFromDb()) { newData ->
setValue(Resource.success(newData))
}
}
}
is ApiErrorResponse -> {
onFetchFailed()
result.addSource(dbSource) { newData ->
setValue(Resource.error(response.errorMessage, newData))
}
}
}
}
}
}
NetworkBoundResource. Mis comentarios son más generales: en mi humilde opinión, una implementación de repositorio de Kotlin debería exponer API relacionadas con las rutinas.
LiveDatacarece del poder de las rutinas RxJava o Kotlin. LiveDataes muy bueno para las comunicaciones de "última milla" a la actividad o fragmento, y fue diseñado con eso en mente. Y para aplicaciones pequeñas, si desea omitir repositorios y simplemente ViewModelhablar directamente con un RoomDatabase, LiveDataestá bien.
suspendfunciones, o retornoChannel/Flowobjetos, dependiendo de la naturaleza de la API. Las corutinas reales se configuran en el modelo de vista.LiveDataes introducido por el modelo de vista, no por el repositorio.