如何在Kotlin Flow的catch块中发射Error状态?类型不匹配问题
Kotlin Flow中Catch块无法发射Error状态的原因与解决方法
问题原因
你的代码中第二个map操作会将Flow的类型从Flow<List<Review>>推断为Flow<State.Success<List<Review>>>——因为map的返回值是明确的State.Success实例。而State.Error属于State<Nothing>类型,虽然State<Nothing>是State<List<Review>>的协变子类,但当前Flow的泛型已经被限定为更具体的State.Success<List<Review>>,并非父类型State<List<Review>>,因此在catch块中发射State.Error会触发类型不匹配错误。
解决方法
方法一:显式指定Map操作的返回类型
通过显式声明map的返回类型为State<List<Review>>,让Flow的泛型保持为父类型,从而兼容State.Error的发射:
suspend fun getReviews(movieId: Long): Flow<State<List<Review>>> = withContext(IO) { flow { emit(api.getReviews(movieId)) } .map { it.sortedWith { item, _ -> if (item.userId == pref.getUserId()) -1 else 0 } } .map<_, State<List<Review>>> { State.Success(it) } .catch { error -> emit(State.Error(error)) Timber.e(error) } }
方法二:使用Transform替代Map
transform操作符支持发射任意符合泛型的元素,比map更灵活,能直接在其中发射State.Success,同时让Flow保持State<List<Review>>的泛型:
suspend fun getReviews(movieId: Long): Flow<State<List<Review>>> = withContext(IO) { flow { emit(api.getReviews(movieId)) } .map { it.sortedWith { item, _ -> if (item.userId == pref.getUserId()) -1 else 0 } } .transform { data -> emit(State.Success(data)) } .catch { error -> emit(State.Error(error)) Timber.e(error) } }
方法三:用Flow构建器包裹完整逻辑
将所有逻辑放在flow构建器内部,更直观地控制状态发射,同时自然兼容异常处理:
suspend fun getReviews(movieId: Long): Flow<State<List<Review>>> = withContext(IO) { flow { // 可选:发射加载状态 emit(State.Loading()) val sortedReviews = api.getReviews(movieId) .sortedWith { item, _ -> if (item.userId == pref.getUserId()) -1 else 0 } emit(State.Success(sortedReviews)) }.catch { error -> emit(State.Error(error)) Timber.e(error) } }
内容的提问来源于stack exchange,提问作者Samuel Robert
相关产品推荐
相关产品推荐

