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

如何在Kotlin中从回调返回值并将结果传递至ViewModel?

解决方案1:用协程挂起函数转换回调

把回调式的异步API包装成挂起函数,就能在ViewModel的协程作用域里同步处理结果,这是最符合Kotlin协程生态的写法:

1. 包装回调为挂起函数

在你的API封装类/Repository中,用suspendCancellableCoroutine将回调转换为挂起函数:

suspend fun signInWithABC(): Result<OAuthToken> = suspendCancellableCoroutine { continuation ->
    abcApi.signIn { token, error ->
        val result = when {
            error != null -> Result.failure(error)
            token != null -> Result.success(token)
            else -> Result.failure(IllegalStateException("Token和Error均为空"))
        }
        continuation.resume(result)
    }

    // 可选:如果API支持取消,这里处理协程取消时的资源释放
    continuation.invokeOnCancellation {
        // abcApi.cancelSignIn() // 若API提供取消方法,在此调用
    }
}

2. 在ViewModel中调用

借助viewModelScope启动协程,直接获取并处理结果:

class AuthViewModel : ViewModel() {
    // 用StateFlow暴露UI状态给界面
    val authState = MutableStateFlow<AuthState>(AuthState.Idle)

    fun handleSignIn() {
        viewModelScope.launch {
            authState.value = AuthState.Loading
            val result = signInWithABC()
            result.fold(
                onSuccess = { token ->
                    authState.value = AuthState.Success(token)
                    // 处理成功逻辑:如保存token到DataStore、跳转到首页等
                },
                onFailure = { error ->
                    authState.value = AuthState.Error(error.message ?: "登录失败")
                    // 处理错误逻辑:如提示用户、记录日志等
                }
            )
        }
    }
}

// 定义UI状态密封类,规范状态类型
sealed class AuthState {
    object Idle : AuthState()
    object Loading : AuthState()
    data class Success(val token: OAuthToken) : AuthState()
    data class Error(val message: String) : AuthState()
}
解决方案2:用StateFlow直接传递结果

如果不想用挂起函数,也可以在封装类中定义StateFlow,回调触发时更新Flow,ViewModel收集状态变化:

1. 在封装类中定义StateFlow

class AuthRepository {
    private val _signInResult = MutableStateFlow<Result<OAuthToken>?>(null)
    // 对外暴露只读的StateFlow
    val signInResult: StateFlow<Result<OAuthToken>?> = _signInResult

    fun signInWithABC() {
        abcApi.signIn { token, error ->
            val result = when {
                error != null -> Result.failure(error)
                token != null -> Result.success(token)
                else -> Result.failure(IllegalStateException("Token和Error均为空"))
            }
            _signInResult.value = result
        }
    }
}

2. 在ViewModel中收集Flow

class AuthViewModel(private val authRepo: AuthRepository) : ViewModel() {
    val authState = MutableStateFlow<AuthState>(AuthState.Idle)

    init {
        // 监听登录结果的变化
        viewModelScope.launch {
            authRepo.signInResult.collect { result ->
                result?.let {
                    authState.value = when {
                        it.isSuccess -> AuthState.Success(it.getOrThrow())
                        else -> AuthState.Error(it.exceptionOrNull()?.message ?: "登录失败")
                    }
                }
            }
        }
    }

    fun handleSignIn() {
        authState.value = AuthState.Loading
        authRepo.signInWithABC()
    }
}
为什么你的原有写法不可行?

你尝试直接返回Result是忽略了异步操作的本质:abcApi.signIn是异步执行的,函数调用后会立刻返回,此时回调还未触发,根本拿不到结果。必须通过协程(挂起函数)或数据流(StateFlow/LiveData)来处理异步结果的传递。

内容的提问来源于stack exchange,提问作者c-an

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 13:15:33