Haben Sie Ideen, wie Sie ein Repository-Muster mit NetworkBoundResource- und Kotlin-Coroutinen implementieren können ? Ich weiß, dass wir mit einem GlobalScope eine Coroutine starten können, aber dies kann zu einem Coroutine-Leck führen. Ich möchte ein viewModelScope als Parameter übergeben, aber es ist etwas schwierig, wenn es um die Implementierung geht (da mein Repository kein CoroutineScope eines ViewModel kennt).
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
. Meine Kommentare sind allgemeiner: IMHO sollte eine Kotlin-Repository-Implementierung Coroutinen-bezogene APIs verfügbar machen.
suspend
Funktionen oder RückgabeChannel
/Flow
Objekte verfügbar machen, abhängig von der Art der API. Die eigentlichen Coroutinen werden dann im Ansichtsmodell eingerichtet.LiveData
wird vom Ansichtsmodell eingeführt, nicht vom Repository.