直到完成另一项操作之前,emitAll? [英] emitAll until another operation is done?

查看:129
本文介绍了直到完成另一项操作之前,emitAll?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Android应用中使用以下代码将数据从远程源加载到本地数据库缓存中.

I'm using the following code in my Android app to load data from a remote source into a local database cache.

inline fun <ResultType, RequestType> networkBoundResource(
    crossinline query: () -> Flow<ResultType>,
    crossinline fetch: suspend () -> RequestType,
    crossinline saveFetchResult: suspend (RequestType) -> Unit,
    crossinline onFetchSuccess: () -> Unit = { },
    crossinline onFetchFailed: (Throwable) -> Unit = { },
    crossinline shouldFetch: (ResultType) -> Boolean = { true }
) = flow {
    val data = query().first()

    val flow = if (shouldFetch(data)) {
        emit(Resource.(data))

        try {
            // this could take a while, I want to keep getting updates meanwhile
            saveFetchResult(fetch())
            onFetchSuccess()
            query().map { Resource.Success(it) }
        } catch (t: Throwable) {
            onFetchFailed(t)
            query().map { Resource.Error(t, it) }
        }
    } else {
        query().map { Resource.Success(it) }
    }
    emitAll(flow)
}

query是一个数据库查询,不断通过emitAll发出数据库更新,直到我们再次调用此方法为止.

The query is a database query that keeps emitting database updates through emitAll until we call this method again.

此设置的问题是Resource.Loading仅包含一个快照".的当前数据(first()),直到我们到达try/catch块的末尾并调用emitAll之前,我们将不会收到任何数据库更新.但是我想在Loading仍在进行时继续接收数据库更新.但是,我不能只在Resource.Loading上调用emitAll,因为这会阻塞整个流程.

The problem with this setup is that Resource.Loading only contains a "snapshot" of the current data (first()) and we won't receive any database updates until we get to the end of the try/catch block and call emitAll. But I would like to keep receiving database updates while Loading is still in progress. However, I can't just call emitAll on Resource.Loading because it would block the whole Flow.

是否可以在try块完成后调用Loading上的emitAll,然后切换到Success/Error?

Is there a way to call emitAll on Loading and then switch to Success/Error once the try block has finished?

推荐答案

我仅对此进行了简单的测试以验证它,但是看起来您可以侦听查询并发出它在根据外部Flow的上下文新发布的协程-功能中的其他工作将继续进行,不受阻碍.完成其他工作后,可以取消侦听查询的协程.例如:

I've only done simple testing on this to validate it, but it looks like you can listen to the query and emit any/all data it propagates in a newly launched coroutine based on the outer Flow's context -- the other work in the function will continue, unblocked. Once that other work is done, the coroutine that's listening to the query can be cancelled. For example:

inline fun <ResultType, RequestType> networkBoundResource(
    crossinline query: () -> Flow<ResultType>,
    crossinline fetch: suspend () -> RequestType,
    crossinline saveFetchResult: suspend (RequestType) -> Unit,
    crossinline onFetchFailed: (Throwable) -> Unit = { },
    crossinline shouldFetch: (ResultType) -> Boolean = { true }
): Flow<Resource<ResultType>> = flow {
    emit(Resource.Loading())
    val data = query().first()

    val flow = if (shouldFetch(data)) {
        val flowContext = currentCoroutineContext()
        val loading: Job = coroutineScope {
            launch(flowContext) {
                query().map { Resource.Loading(it) }
                    .collect { withContext(flowContext) { emit(it) } }
            }
        }

        try {
            val request = fetch()
            loading.cancel()
            saveFetchResult(request)
            query().map { Resource.Success(it) }
        } catch (throwable: Throwable) {
            loading.cancel()
            onFetchFailed(throwable)
            query().map { Resource.Error(throwable, it) }
        }
    } else {
        query().map { Resource.Success(it) }
    }

    emitAll(flow)
}

让我知道是否可行!

这篇关于直到完成另一项操作之前,emitAll?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆