Kotlin Flow代码块未执行 调用控制权返回ViewModel问题排查
Kotlin协程Flow代码块未执行问题排查
核心成因
- 最直接原因:Flow是冷流,你没有调用末端操作符触发流执行。
onEach属于中间操作符,仅做数据转换/侧处理逻辑,不会启动flow{}代码块的执行,只有调用collect、collectLatest、first()这类末端操作符时,Flow才会真正开始运行生产数据的逻辑。你当前ViewModel层的代码只调用了onEach,没有加末端收集操作,所以Repository层的flow{}代码块根本不会被触发,调用后控制权直接返回。 - 隐藏问题:你当前Repository层的Flow实现本身不符合异步回调场景的使用规范,就算加上
collect触发流执行,flow{}代码块在调用完ftpClient.connect后会立刻执行完毕退出,无法等待异步回调返回,onSuccess/onFail里的结果根本没法发射到流中。
修正方案
1. 补全ViewModel层的Flow末端收集逻辑
在onEach链式调用后加上collect()触发流执行,修正后代码如下:
fun getFilesFromServer() { viewModelScope.launch(Dispatchers.IO) { ftpRepository.getFilesFromServer() .onEach { state -> when (state) { is Resource.Loading -> { liveData.postValue(Resource.Loading()) } is Resource.Success -> liveData.postValue(state) is Resource.Error -> liveData.postValue(state) } } .collect() // 必须添加末端操作符,才会触发Flow执行 } }
2. 替换Repository层的flow实现为callbackFlow
针对FTP连接这种异步回调场景,使用callbackFlow来实现回调到Flow的转换,保证回调结果可以正常发射、流生命周期和协程绑定,修正后代码如下:
// 注意这里不需要加suspend修饰符,callbackFlow返回的冷流本身在协程上下文执行 override fun getFilesFromServer(): Flow<Resource<Response>> = callbackFlow { // 首先发射加载状态 trySend(Resource.Loading()) ftpClient.connect( Constants.SERVER_IP, Constants.PORT, Constants.USER_NAME, Constants.PASSWORD, object : OnEZFtpCallBack<Void?> { override fun onSuccess(response: Void?) { val fileList = requestFtpFileList() trySend(Resource.Success(fileList)) close() // 结果发射完成后关闭流 } override fun onFail(code: Int, msg: String) { trySend(Resource.Error(code, msg)) close() // 请求失败时关闭流 } } ) // 流被取消时主动释放FTP连接,避免资源泄漏 awaitClose { // 替换成你项目中实际的FTP断开连接方法 ftpClient.disconnect() } }
内容的提问来源于stack exchange,提问作者shehzy
相关产品推荐
相关产品推荐

