Kotlin Flow的onStart()未触发?如何获取Result.Loading状态?
问题原因与解决方案
问题根源
你的代码中Result.Loading未被打印,是因为**debounce操作符的位置错误**,导致Loading事件被抑制了。
debounce的作用是在指定时间窗口内,丢弃先发射的事件,只保留最后一个。当onStart发射Loading后,原Flow很快就发射了数据并被映射为Success,debounce会直接丢弃掉先出现的Loading,只保留后续的Success事件,因此你看不到Loading的打印日志。
解决方案
调整操作符的顺序,让debounce仅作用于业务数据流(需要防抖的业务数据),而Loading状态的发射不经过debounce处理。具体修改如下:
补充缺失的常量定义
原代码缺少RETRY_TIME_IN_MILLIS和RETRY_ATTEMPT_COUNT的定义,先补充:
private const val RETRY_TIME_IN_MILLIS = 1000L private const val RETRY_ATTEMPT_COUNT = 3
修改asResult函数的操作符顺序
@OptIn(kotlinx.coroutines.FlowPreview::class) fun <T> Flow<T>.asResult(): Flow<Result<T>> { return this // 先对原业务流做防抖处理 .debounce(RETRY_TIME_IN_MILLIS * RETRY_ATTEMPT_COUNT) // 重试逻辑仅作用于业务流 .retryWhen { cause, attempt -> if (cause is IOException && attempt < RETRY_ATTEMPT_COUNT) { delay(RETRY_TIME_IN_MILLIS) true } else { false } } // 将业务数据映射为Success状态 .map<T, Result<T>> { Result.Success(it) } // 在流启动时发射Loading,此事件不经过debounce .onStart { emit(Result.Loading) } // 捕获所有异常并发射Error状态 .catch { emit(Result.Error(it)) } }
修改后的效果
运行修改后的代码,你会看到首先打印Result Loading in viewmodel,随后打印业务数据的Success日志,符合预期逻辑。
内容的提问来源于stack exchange,提问作者Po-Ting Huang
相关产品推荐
相关产品推荐

