Kotlin协程Flow使用flow正常asFlow调用报两类错误问题
问题产生原因
两个报错分别由不同的误用导致:
- 挂起函数调用非法错误:
fetchComplexSearch是suspend修饰的挂起函数,仅允许在协程作用域或其他挂起函数内调用。你之前用flow{}构建器时,代码块本身属于挂起上下文,自带协程作用域,因此可以正常调用挂起函数;但你在asFlow版本的实现中,直接在普通函数的返回语句里同步调用挂起函数,既不在协程作用域内,当前complexSearch方法也不是挂起函数,自然触发调用限制报错。 - 类型不匹配错误:Kotlin针对
Iterable类型提供的asFlow()扩展函数,逻辑是将集合内的单个元素逐个作为流元素发射,而非把整个集合作为单个元素发射。你的代码中resultModel.results.map{}执行后得到的是List<ComplexSearchEntity>类型,直接对这个List调用asFlow(),会把列表里的每个ComplexSearchEntity逐个发射,最终返回Flow<ComplexSearchEntity>,和方法要求返回的Flow<List<ComplexSearchEntity>>类型不匹配。
修复方案
asFlow()本身不会提供协程上下文,仅负责将已有的计算结果/函数转换成流,修复时可以选择以下两种正确实现:
方案1:使用函数类型的asFlow扩展(保留asFlow写法)
将挂起请求+数据映射的逻辑整体包裹在suspend函数块中,再调用针对suspend () -> T的asFlow()扩展,这个版本的asFlow会把函数块的返回值整体作为单个流元素发射,既符合类型要求,也能在suspend块的挂起上下文里正常调用挂起函数:
override fun complexSearch(apiKey: String): Flow<List<ComplexSearchEntity>> { return suspend { val resultModel = foodService.fetchComplexSearch(apiKey) resultModel.results.map { mapperDataToDomain.map(it) } }.asFlow() }
方案2:保留原有flow构建器写法
你最初用flow{}实现的代码本身是完全正确的,逻辑更直观,也是Flow的常规实现方式,不需要额外修改:
override fun complexSearch(apiKey: String): Flow<List<ComplexSearchEntity>> { return flow { val resultModel = foodService.fetchComplexSearch(apiKey) val listOfComplexSearchEntity = resultModel.results.map { complexSearchModel -> mapperDataToDomain.map(complexSearchModel) } emit(listOfComplexSearchEntity) } }
注意:如果你的业务场景真的需要把食谱列表拆成单个食谱逐个发射,才需要用到
Iterable.asFlow(),此时需要把方法返回值改成Flow<ComplexSearchEntity>,同时把挂起调用放到协程上下文里。
内容的提问来源于stack exchange,提问作者ant2009
相关产品推荐
相关产品推荐

