【问题标题】:Kotlin coroutines - start another task if after some time the first one doesn't finishKotlin 协程 - 如果一段时间后第一个任务没有完成,则启动另一个任务
【发布时间】:2019-07-19 22:54:17
【问题描述】:

我正在使用 Kotlin 协程从服务器获取数据,我正在将延迟传递给其他函数。如果服务器在 2000 毫秒内没有给出答案,我想从本地 Room DB 中检索对象(如果它存在于本地数据库中),但是如果我最终从服务器接收到数据,我想保存在在本地数据库中以供将来调用。我怎样才能做到这一点?我想过使用withTimeout,但是在这种情况下,超时后没有等待服务器的响应。

override fun getDocument(): Deferred<Document> {
    return GlobalScope.async {
        withTimeoutOrNull(timeOut) {
            serverC.getDocument().await()
        } ?: dbC.getDocument().await()
    }
}

我想出了一个主意:

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()
        }
    }
}

【问题讨论】:

    标签: android database kotlin coroutine kotlin-coroutines


    【解决方案1】:

    我建议使用kotlinx.coroutines 库中的select 表达式。
    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
    
                }
            }
        }
    }
    

    选择表达式会随着来自网络的onAwait 信号或超时而恢复。在这种情况下,我们返回本地数据。

    您可能还希望以块的形式加载文档,因为Channels 也可能会有所帮助 https://kotlinlang.org/docs/reference/coroutines/channels.html

    最后,我们在示例中使用了 kotlinx.coroutines 的 Experimental API,函数 onTimeout 可能会在库的未来版本中发生变化

    【讨论】:

    • 谢谢,但在这种情况下,100 毫秒后,服务器作业被取消。在这种情况下,我想实现的是返回本地值,同时也将来自服务器的数据在到达时保存在数据库中。
    • 我建议让这两个作业都贡献给Channel&lt;Document&gt;,这样它就会立即将结果传递给请求者,否则,如果服务器请求运行得比那个慢,被调用者在 2 秒后将没有结果
    猜你喜欢
    • 2017-09-12
    • 1970-01-01
    • 1970-01-01
    • 2019-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-10
    • 1970-01-01
    相关资源
    最近更新 更多