I am using Kotlin coroutines to get data from the server, I am passing the deferred over to other functions. In case the server doesn't give an answer in 2000 ms I would like to retrive the object from a local Room DB (if it exists in a local database), but if I finally receive data from the server I would like to save in in a local DB for future calls. How can I acheive that? I thought about using withTimeout, but in this situation, there is no waiting for a response from the server after timeout.
override fun getDocument(): Deferred<Document> {
return GlobalScope.async {
withTimeoutOrNull(timeOut) {
serverC.getDocument().await()
} ?: dbC.getDocument().await()
}
}
An idea I came up with:
fun getDocuments(): Deferred<Array<Document>> {
return GlobalScope.async {
val s = serverC.getDocuments()
delay(2000)
if (!s.isCompleted) {
GlobalScope.launch {
dbC.addDocuments(s.await())
}
val fromDb = dbC.getDocuments().await()
if (fromDb != null) {
fromDb
} else {
s.await()
}
} else {
s.await()
}
}
}
I recommend using the select expression from the kotlinx.coroutines library.
https://kotlinlang.org/docs/reference/coroutines/select-expression.html
fun CoroutineScope.getDocumentsRemote(): Deferred<List<Document>>
fun CoroutineScope.getDocumentsLocal(): Deferred<List<Document>>
@UseExperimental(ExperimentalCoroutinesApi::class)
fun CoroutineScope.getDocuments(): Deferred<List<Document>> = async {
supervisorScope {
val documents = getDocumentsRemote()
select<List<Document>> {
onTimeout(100) {
documents.cancel()
getDocumentsLocal().await()
}
documents.onAwait {
it
}
}
}
}
The select expression resumes either with the onAwait signal from the network or with the timeout. We return the local data in that case.
You may want to load documents in chunks as well, for that Channels may help too
https://kotlinlang.org/docs/reference/coroutines/channels.html
And lastly, we use an Experimental API of kotlinx.coroutines in the example, the function onTimeout may change in the future versions of the library