Android MVI架构ViewModel响应检查代码冗余优化咨询
优化MVI架构ViewModel中HTTP响应处理的冗余代码
核心思路
把重复的HTTP状态码分支逻辑抽成通用处理函数,让ViewModel里的请求函数只聚焦业务数据的转换,不用重复写状态判断逻辑。以下是具体实现方案:
先看原来的冗余代码示例
class MyViewModel(private val repo: MyRepository) : ViewModel() { private val _uiState = MutableStateFlow<UiState>(UiState.Idle) val uiState = _uiState.asStateFlow() fun fetchData() = viewModelScope.launch { _uiState.value = UiState.Loading val response = repo.fetchData() when (response.code) { in 200..202 -> _uiState.value = UiState.Success(response.data) in 400..499 -> _uiState.value = UiState.Error("客户端错误:${response.message}") in 500..599 -> _uiState.value = UiState.Error("服务器错误:${response.message}") else -> _uiState.value = UiState.Error("未知错误") } } fun submitData(data: Data) = viewModelScope.launch { _uiState.value = UiState.Loading val response = repo.submitData(data) when (response.code) { in 200..202 -> _uiState.value = UiState.SubmitSuccess in 400..499 -> _uiState.value = UiState.Error("客户端错误:${response.message}") in 500..599 -> _uiState.value = UiState.Error("服务器错误:${response.message}") else -> _uiState.value = UiState.Error("未知错误") } } }
方案1:封装通用响应处理函数
在ViewModel内部或单独的扩展文件里,写一个通用函数统一处理状态码和UI状态更新:
// 可放在ViewModel基类或扩展文件中 fun <T> ViewModel.handleHttpResponse( loadingState: UiState, request: suspend () -> HttpResponse<T>, onSuccess: (T) -> UiState ) = viewModelScope.launch { _uiState.value = loadingState try { val response = request() _uiState.value = when (response.code) { in 200..202 -> onSuccess(response.data) in 400..499 -> UiState.Error("客户端错误:${response.message}") in 500..599 -> UiState.Error("服务器错误:${response.message}") else -> UiState.Error("未知错误") } } catch (e: Exception) { _uiState.value = UiState.Error("网络异常:${e.message ?: "未知错误"}") } }
重构后的ViewModel请求函数
class MyViewModel(private val repo: MyRepository) : ViewModel() { private val _uiState = MutableStateFlow<UiState>(UiState.Idle) val uiState = _uiState.asStateFlow() fun fetchData() = handleHttpResponse( loadingState = UiState.Loading, request = repo::fetchData, onSuccess = { UiState.Success(it) } ) fun submitData(data: Data) = handleHttpResponse( loadingState = UiState.Loading, request = { repo.submitData(data) }, onSuccess = { UiState.SubmitSuccess } ) }
方案2:用Flow封装响应式请求流
如果更贴合Flow的响应式特性,可以把请求封装成Flow,统一处理响应转换:
// 通用HTTP响应转换Flow fun <T> httpRequestFlow(request: suspend () -> HttpResponse<T>): Flow<UiState> = flow { val response = request() emit( when (response.code) { in 200..202 -> UiState.Success(response.data) in 400..499 -> UiState.Error("客户端错误:${response.message}") in 500..599 -> UiState.Error("服务器错误:${response.message}") else -> UiState.Error("未知错误") } ) }.catch { e -> emit(UiState.Error("网络异常:${e.message ?: "未知错误"}")) }.onStart { emit(UiState.Loading) }
对应ViewModel用法
fun fetchData() = viewModelScope.launch { httpRequestFlow(repo::fetchData) .collect { _uiState.value = it } } fun submitData(data: Data) = viewModelScope.launch { httpRequestFlow { repo.submitData(data) } .map { // 针对提交成功的特殊状态转换 if (it is UiState.Success<*>) UiState.SubmitSuccess else it } .collect { _uiState.value = it } }
优化后的优势
- 消除重复:所有状态码判断逻辑集中在一处,后续修改只需调整通用函数
- 关注点分离:请求函数只需要处理业务相关的UI状态转换,不用管通用响应逻辑
- 统一异常处理:网络异常、未知错误等都在通用逻辑里处理,避免每个请求写try-catch
- 扩展性强:后续新增状态码分支(比如3xx重定向),只需修改通用函数即可
内容的提问来源于stack exchange,提问作者Noah
相关产品推荐
相关产品推荐

