You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin Flow仅发射Loading/Loaded状态,Success/Error未触发问题排查

问题描述

我有一个BaseUseCase类用于编排状态,代码如下:

abstract class BaseUseCase<T, in P: UseCaseParameters> {

    protected abstract suspend fun FlowCollector<Result<T>>.run(params: P)

    operator fun invoke(params: P) =
        flow {
            emit(State.Loading)
            run(params)
            emit(State.Loaded)
        }.flowOn(Dispatchers.IO)
}

预期Flow.collect{}的输出为:

State.Loading
State.Success / State.Error // 获取成功或错误数据
State.Loaded

此前该实现用于API调用等场景均正常,但在读取Assets中JSON文件并发射到Flow的场景下,仅能发射Loading和Loaded状态。

以下是其余实现代码:

ViewModel:

private fun getAllCards() {
        viewModelScope.launch {
            getAllCardsUseCase(None()).collect {
                val printData: String = when (it) {
                    is State -> it.toString()
                    is Failure -> it.errorData.message.toString()
                    is Success -> {
                        it.successData.cardList.first().name }
                }
                Timber.d("ALL CARDS RESPONSE = $printData")
            }
        }
    }

UseCase:

class GetAllCardsUseCase<T : ViewEntity> @Inject constructor(
    private val mapper: @JvmSuppressWildcards Mapper<ArrayList<Card>, T>,
    private val cardRepository: CardRepository
) : BaseUseCase<T, None>() {
    override suspend fun FlowCollector<Result<T>>.run(params: None) {
        cardRepository.getCardList(mapper = mapper)
    }
}

Repository:

override suspend fun <T : ViewEntity> getCardList(mapper: Mapper<ArrayList<Card>, T>): Result<T> =
    readCardListFromFile()?.let {
        Success(successData = mapper.convert(it))
    } ?: run {
        Failure(errorData = ParsingError())
    }

JSON数据已成功读取并映射为模型,getCardList()也按预期返回了Success状态,但该状态从未被发射。请问我遗漏了什么?

问题原因与解决方法

核心问题

你在GetAllCardsUseCase的run方法里,仅调用cardRepository.getCardList()获取到了Result<T>对象,但没有将这个结果发射到Flow中。

之前API调用场景正常,是因为对应UseCase的run方法里执行了emit(...)来发射成功/失败状态,而当前读取Assets的UseCase漏掉了这关键一步。

修复代码

修改GetAllCardsUseCase的run方法,添加emit操作:

override suspend fun FlowCollector<Result<T>>.run(params: None) {
    val result = cardRepository.getCardList(mapper = mapper)
    emit(result) // 关键:将Repository返回的结果发射到Flow中
}

补充说明

  • BaseUseCase的flow块中,run(params)只是执行你定义的业务逻辑,只有主动调用emit,才能把中间的Success/Failure状态传递给下游的collector。
  • 原代码里run(params)仅执行了Repository的方法,拿到结果后未做发射操作,导致Flow只发射了Loading和Loaded,中间的业务结果被直接丢弃。

内容的提问来源于stack exchange,提问作者sgurdag

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 17:15:15