违反了流异常透明度:检测到来自另一个协程的发射

25 android android-jetpack kotlin-coroutines

我正在尝试在我的项目中实现 NetworkBoundResource 类,这就是我正在尝试的。一切正常,获得响应,缓存,但是当我在 flowBuilder 中发出值时,它崩溃并显示此错误。

我收到错误:

    Emission from another coroutine is detected.
    Child of ProducerCoroutine{Active}@df26eb9, expected child of FlowCoroutine{Active}@a0bb2fe.
    FlowCollector is not thread-safe and concurrent emissions are prohibited.
    To mitigate this restriction please use 'channelFlow' builder instead of 'flow')' has been detected.
                  Emissions from 'catch' blocks are prohibited in order to avoid unspecified behaviour, 'Flow.catch' operator can be used instead.
                  For a more detailed explanation, please refer to Flow documentation.
Run Code Online (Sandbox Code Playgroud)

网络绑定资源类:


abstract class NetworkBoundResource<ResultType, RequestType> {

    fun invoke(): Flow<Resource<ResultType>> = flow {
        val rawData = loadFromDb()

        if (shouldFetch(rawData)) {
            fetchDataFromServer()
                .onStart { emit(Resource.loading(rawData)) } // emit() causing issue
                .catch { emit(Resource.error(it, null)) } // emit() causing issue
                .collectLatest { }
        }
    }

    // Save API response result into the database
    protected abstract suspend fun cacheInDb(items: RequestType)

    // Need to fetch data from server or not.
    protected abstract fun shouldFetch(data: ResultType?): Boolean

    // Show cached data from the database.
    protected abstract suspend fun loadFromDb(): ResultType

    // Fetch the data from server.
    protected abstract suspend fun fetchDataFromServer(): Flow<ApiResponse<List<Category>>>

    // when the fetch fails.
    protected open fun onFetchFailed() {}
}
Run Code Online (Sandbox Code Playgroud)

存储库类:

    fun getCategories(): Flow<Resource<List<Category>>> {
        return object : NetworkBoundResource<List<Category>, List<Category>>() {

            override suspend fun cacheInDb(items: List<Category>) {
                withContext(Dispatchers.IO) { database.getCategories().insert(items) }
            }

            override fun shouldFetch(data: List<Category>?): Boolean {
                return true
            }

            override suspend fun loadFromDb(): List<Category> {
                return withContext(Dispatchers.IO) { database.getCategories().read() }
            }

            override suspend fun fetchDataFromServer(): Flow<ApiResponse<List<Category>>> {
                return flow { emit(RetrofitModule.getCategories()) }
            }

        }.invoke()
    }
Run Code Online (Sandbox Code Playgroud)

我的ViewModel类:

    init {
        viewModelScope.launch {
            repository.getCategories().collectLatest {
                if(it.data!=null){
                    _categories.value = it.data
                    Log.d("appDebug", " ViewModel : $it")
                }
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

Nag*_*obi 48

正如例外情况所示,冷流不允许emit()同时进行。您有两个选择:

  • 替换flow { }channelFlow { }并发送值send()(在您的情况下可能更容易)
  • 确保没有emit()同时调用