Kotlin中Flow collect后also代码块未执行的问题排查
问题分析与修正方案
你的代码存在两个核心问题:
collect阻塞导致后续代码无法执行
Room返回的Flow是持续监听数据库变化的流,collect作为挂起函数会一直阻塞当前协程,直到Flow被主动取消。因此collect后面的.also代码块、以及最后的forEach循环永远不会运行——协程会一直卡在collect步骤等待数据库的新数据。数据筛选时机错误
即便Flow能结束,also块的执行时机也在collect完成之后,而jobsDataList是在collect的lambda中每次接收数据时赋值的,这时also里拿到的jobsDataList要么是空值,要么是最后一次赋值的结果,完全无法响应每次数据库的更新。
修正后的代码方案
方案1:在collect内部处理筛选(简单直接)
直接把筛选逻辑放到collect的lambda里,每次数据库更新都重新计算:
viewModelScope.launch { repo.getAllJobsFlow().collect { jobs -> jobsDataList = jobs jobsListUpdateDatabase.postValue(jobs) // 每次拿到新数据后立即执行筛选 appliedAndAcceptedDataList = jobs.filter { job -> job.workers.any { worker -> worker.worker_id == PosterPalApplication.USER_ID } } // 打印筛选结果 appliedAndAcceptedDataList.forEach { Log.d(TAG, "job title = ${it.job.title} with worker") } } }
方案2:用Flow操作符在后台处理筛选(满足非UI线程需求)
如果要让筛选逻辑在后台线程执行,用map操作符结合flowOn指定调度器,把数据处理移到后台,最后在主线程收集结果:
viewModelScope.launch { repo.getAllJobsFlow() // 在后台线程执行筛选逻辑 .map { jobs -> jobs.filter { job -> job.workers.any { worker -> worker.worker_id == PosterPalApplication.USER_ID } } } // 指定map操作的执行线程为IO线程 .flowOn(Dispatchers.IO) // 在主线程收集处理后的结果 .collect { filteredJobs -> appliedAndAcceptedDataList = filteredJobs filteredJobs.forEach { Log.d(TAG, "job title = ${it.job.title} with worker") } } }
补充说明
如果不需要持续监听数据库变化,只是一次性获取数据,可以改用返回List<Job>的getAllJobs(),配合withContext在后台执行筛选:
viewModelScope.launch { val jobs = withContext(Dispatchers.IO) { repo.getAllJobs() } jobsDataList = jobs jobsListUpdateDatabase.postValue(jobs) appliedAndAcceptedDataList = withContext(Dispatchers.IO) { jobs.filter { job -> job.workers.any { worker -> worker.worker_id == PosterPalApplication.USER_ID } } } appliedAndAcceptedDataList.forEach { Log.d(TAG, "job title = ${it.job.title} with worker") } }
内容的提问来源于stack exchange,提问作者user1743524
相关产品推荐
相关产品推荐

