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

如何为ViewModel和Retrofit创建LiveData实现API请求结果监听

解决步骤

1. 修复Retrofit接口定义错误

当前ApiCallsService中suspend方法返回Call<*>属于错误用法,suspend方法不需要通过Call包裹返回值,直接返回数据实体即可,修改后代码如下:

interface ApiCallsService {
    @GET(".")
    suspend fun apiCalls(
        @Query("param1") param1: String,
        @Query("param2") param2: String,
        @Query("param3") param3: String
    ): CustomDataClass // 去掉Call包裹,直接返回自定义数据类
}

注意:原有ViewModel代码中调用接口时误用了接口名ApiCallsService作为方法名,实际应该调用接口内定义的apiCalls方法,下述代码已修正该问题。

2. 修改ViewModel添加LiveData相关逻辑

我们可以用密封类封装接口请求状态,方便在视图层处理加载、成功、失败三种场景,也可以直接返回数据类,两种实现如下:

可选:定义请求状态密封类(推荐)

sealed class ApiResult<out T> {
    object Loading : ApiResult<Nothing>()
    data class Success<out T>(val data: T) : ApiResult<T>()
    data class Failure(val errorMsg: String) : ApiResult<Nothing>()
}

带状态封装的ViewModel实现

class ApiViewModel : ViewModel() {
    // 内部可变LiveData,用于存储请求结果
    private val _apiResult = MutableLiveData<ApiResult<CustomDataClass>>()
    // 对外暴露不可变LiveData,供视图层观察
    val apiResult: LiveData<ApiResult<CustomDataClass>> = _apiResult

    fun getApiResults(param1: String, param2: String, param3: String): LiveData<ApiResult<CustomDataClass>> {
        viewModelScope.launch {
            // 先发送加载中状态
            _apiResult.postValue(ApiResult.Loading)
            try {
                val listResult = ApiCalls.retrofitService.apiCalls(param1, param2, param3)
                // 请求成功发送数据
                _apiResult.postValue(ApiResult.Success(listResult))
            } catch (e: Exception) {
                // 请求失败发送错误信息
                _apiResult.postValue(ApiResult.Failure("Failure: ${e.message ?: "未知错误"}"))
            }
        }
        return apiResult
    }
}

简化版ViewModel实现(不需要状态封装)

class ApiViewModel : ViewModel() {
    private val _apiData = MutableLiveData<CustomDataClass?>()
    val apiData: LiveData<CustomDataClass?> = _apiData

    fun getApiResults(param1: String, param2: String, param3: String): LiveData<CustomDataClass?> {
        viewModelScope.launch {
            try {
                val listResult = ApiCalls.retrofitService.apiCalls(param1, param2, param3)
                _apiData.postValue(listResult)
            } catch (e: Exception) {
                // 失败时赋值为null,也可以另外新增字段存储错误信息
                _apiData.postValue(null)
            }
        }
        return apiData
    }
}

3. Fragment中调用示例

完全符合预期的调用写法:

val apiViewModel = ViewModelProvider(this).get(ApiViewModel::class.java)
// 带状态版本的观察逻辑
apiViewModel.getApiResults("val1", "val2", "val3").observe(viewLifecycleOwner) { result ->
    when(result) {
        is ApiResult.Loading -> {
            // 展示加载动画
        }
        is ApiResult.Success -> {
            val data = result.data
            // 拿到数据渲染视图
        }
        is ApiResult.Failure -> {
            val errorMsg = result.errorMsg
            // 展示错误提示
        }
    }
}

// 简化版的观察逻辑
/*
apiViewModel.getApiResults("val1", "val2", "val3").observe(viewLifecycleOwner) { data ->
    data?.let {
        // 渲染数据
    } ?: run {
        // 处理请求失败
    }
}
*/

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 09:57:01