如何为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
相关产品推荐
相关产品推荐

