¿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.
LiveData
carece del poder de las rutinas RxJava o Kotlin. LiveData
es 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 ViewModel
hablar directamente con un RoomDatabase
, LiveData
está bien.
suspend
funciones, o retornoChannel
/Flow
objetos, dependiendo de la naturaleza de la API. Las corutinas reales se configuran en el modelo de vista.LiveData
es introducido por el modelo de vista, no por el repositorio.