网络响应失败时如何为LiveData.setValue()设置合适值?
处理Retrofit请求异常时的LiveData状态设置
在网络请求失败或响应不成功时,直接给LiveData设置null会让UI层难以区分具体状态(是无数据、请求失败还是响应错误)。更合理的做法是用状态封装类包裹数据与状态信息,让LiveData传递明确的请求状态,方便UI层针对性处理。
1. 定义状态封装类
Kotlin 方案(推荐,密封类更简洁)
sealed class Resource<out T> { // 请求成功,携带返回数据 data class Success<out T>(val data: T) : Resource<T>() // 请求失败/响应错误,携带错误信息和错误码(可选) data class Error(val message: String?, val code: Int? = null) : Resource<Nothing>() // 加载中状态(可选,用于显示加载UI) object Loading : Resource<Nothing>() }
Java 方案
如果项目用Java开发,可以用包含状态枚举的通用类:
public class Resource<T> { private final Status status; private final T data; private final String message; private final Integer code; private Resource(Status status, T data, String message, Integer code) { this.status = status; this.data = data; this.message = message; this.code = code; } // 快捷创建成功状态实例 public static <T> Resource<T> success(T data) { return new Resource<>(Status.SUCCESS, data, null, null); } // 快捷创建错误状态实例 public static <T> Resource<T> error(String message, Integer code) { return new Resource<>(Status.ERROR, null, message, code); } // 快捷创建加载中状态实例 public static <T> Resource<T> loading() { return new Resource<>(Status.LOADING, null, null, null); } // 请求状态枚举 public enum Status { SUCCESS, ERROR, LOADING } // getter方法 public Status getStatus() { return status; } public T getData() { return data; } public String getMessage() { return message; } public Integer getCode() { return code; } }
2. 修改ViewModel中的LiveData类型
把原来的MutableLiveData<User>改成MutableLiveData<Resource<User>>,这样就能传递带状态的信息:
// ViewModel中的声明 private MutableLiveData<Resource<User>> userMutableLiveData = new MutableLiveData<>(); public LiveData<Resource<User>> getUserLiveData() { return userMutableLiveData; }
3. 在Retrofit回调中设置对应状态
call.enqueue(new Callback<User>() { @Override public void onResponse(Call<User> call, Response<User> response) { if (response.isSuccessful()) { // 请求成功,封装成功状态 userMutableLiveData.setValue(Resource.success(response.body())); } else { // 响应不成功,解析错误信息 String errorMsg = "请求失败"; int errorCode = response.code(); try { if (response.errorBody() != null) { errorMsg = response.errorBody().string(); } } catch (IOException e) { e.printStackTrace(); errorMsg = "解析错误信息失败"; } // 封装错误状态 userMutableLiveData.setValue(Resource.error(errorMsg, errorCode)); } } @Override public void onFailure(Call<User> call, Throwable t) { // 网络请求失败,封装错误状态 String errorMsg = t.getMessage() != null ? t.getMessage() : "网络连接失败"; userMutableLiveData.setValue(Resource.error(errorMsg, null)); } });
4. UI层根据状态处理
在Activity/Fragment中观察LiveData,根据不同状态更新UI:
viewModel.getUserLiveData().observe(this, resource -> { switch (resource.getStatus()) { case SUCCESS: User user = resource.getData(); // 更新UI显示用户数据 break; case ERROR: String errorMsg = resource.getMessage(); Integer errorCode = resource.getCode(); // 显示错误提示,比如Toast或Snackbar String tip = errorCode != null ? errorMsg + " (错误码:" + errorCode + ")" : errorMsg; Toast.makeText(this, tip, Toast.LENGTH_SHORT).show(); break; case LOADING: // 显示加载中UI,比如ProgressBar break; } });
为什么这么做?
- 避免
null带来的歧义:UI层能明确区分“请求成功但无数据”“响应错误”“网络失败”等场景 - 职责分离:数据模型(User)只承担数据存储,状态管理交给专门的封装类
- 扩展性强:后续可以轻松添加更多状态(比如空数据状态)
内容的提问来源于stack exchange,提问作者Gaganjot Singh
相关产品推荐
相关产品推荐

