You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Result对象抛出异常,在ViewModel中无法捕获的问题

使用Result返回失败结果后,ViewModel无法触发onFailure回调

问题描述

在使用Kotlin Result 对象封装失败结果时,发现ViewModel中无法捕获到UseCase返回的失败状态,onFailure 回调始终不执行。

相关代码

Action.kt

abstract class Action<in Input, out Output> {
    protected abstract suspend fun action(input: Input): Output

    protected open fun dispatcher(): CoroutineDispatcher = Dispatchers.IO

    suspend operator fun invoke(input: Input): Output = withContext(dispatcher()) {
        action(input)
    }
}

IsNewDataToBeFetchedFromServerUseCase.kt

class IsNewDataToBeFetchedFromServerUseCase @Inject constructor(
    @IoDispatcher private val dispatcher: CoroutineDispatcher,
) : Action<Unit, Result<Boolean>>() {
    
    override suspend fun action(input: Unit): Result<Boolean> = withContext(context = dispatcher) {
        return@withContext Result.failure(Exception("Message"))
    }
    
}

ViewModel中的调用代码

useCases.isNewDataToBeFetchedFromServerUseCase.invoke(Unit).onSuccess {
    println("成功回调")
}.onFailure {
    println(it.message) // 此处未执行
}

问题原因

  1. 协程作用域缺失:invoke 是挂起函数,必须在协程上下文内调用。直接在ViewModel中调用挂起函数会导致代码无法正常执行,无法正确获取到Result对象。
  2. 冗余的协程调度器切换:Action类的invoke方法已经通过withContext(dispatcher())切换了调度器,UseCase中重复调用withContext属于多余操作,不会导致问题,但会增加不必要的协程切换开销。

解决方案

1. 在ViewModel的协程作用域内调用挂起函数

使用viewModelScope(AndroidX Lifecycle库提供)启动协程,确保在正确的生命周期内执行挂起逻辑:

viewModelScope.launch {
    useCases.isNewDataToBeFetchedFromServerUseCase.invoke(Unit).onSuccess {
        println("成功回调")
    }.onFailure {
        println(it.message) // 现在可以正常触发
    }
}

2. 移除UseCase中的冗余协程切换

修改UseCase代码,复用Action类的调度器逻辑:

class IsNewDataToBeFetchedFromServerUseCase @Inject constructor(
    @IoDispatcher private val dispatcher: CoroutineDispatcher,
) : Action<Unit, Result<Boolean>>() {
    
    override fun dispatcher(): CoroutineDispatcher = dispatcher

    override suspend fun action(input: Unit): Result<Boolean> {
        return Result.failure(Exception("Message"))
    }
    
}

补充说明

Kotlin Result 是用于封装成功/失败结果的容器,它不会主动抛出异常,仅将失败状态包装在对象内。只有调用Result.getOrThrow()时才会抛出封装的异常。因此只要正确获取到Result对象,onFailure回调就会被触发,核心问题是协程作用域的缺失。

内容的提问来源于stack exchange,提问作者Devrath

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 21:15:56