ViewModel 应该不要处理异常? 更准确地说:ViewModel 不应该处理异常,它只需要"消费结果"。
本文结合实际项目中的常见做法,说明一种更清晰的职责划分: UseCase / Repository 负责处理异常,ViewModel 只关注数据与 UI 状态。
⚠️ 说明:本文中的异常模型是刻意简化的 。 重点不在"异常如何分类",而在于: 只要异常已经在下层被处理并转换成结果,ViewModel 就不应该再关心异常本身。
1. 背景:异常到底该谁来处理?
一个典型的 clean 分层大致如下:
- UI 层(Activity / Fragment / Compose)
- ViewModel
- Domain 层(UseCase)
- Data 层(Repository / DataSource / 网络、数据库等)
常见的疑问是:
ViewModel 拿到 UseCase 或 Repository 的数据,这些底层已经做了异常处理,那 ViewModel 还要再 try/catch 吗?
我的结论是:
如果 UseCase / Repository 已经把异常转换成稳定的数据结果,ViewModel 完全可以只关心"结果",而不直接处理异常对象。
2. 分层职责:谁应该干什么?
2.1 Data / Domain 层(UseCase / Repository)
核心职责:
- 捕获所有底层异常(网络、IO、数据库、第三方 SDK 等)
- 在内部记录日志、上报监控、决定是否重试
- 将异常统一转换为一个稳定、简单、可被上层消费的结果
为了突出 ViewModel 的职责边界,这里使用一个极简的结果模型:
一个简单的 Repository 实现示例如下:
这里已经完成了所有异常相关的工作:
- 捕获异常
- 屏蔽底层实现细节(网络库、异常类型)
- 向上层只暴露一个"成功 / 失败"的结果
2.2 ViewModel 层
核心职责:
- 调用 UseCase / Repository
- 根据返回的结果更新 UI 状态(loading / content / error)
- 只处理结果分支,而不是异常本身
示例代码如下:


可以看到:
- ViewModel 完全没有
try/catch - 不知道发生了什么异常
- 只知道"成功"或"失败"
- 只关心当前应该呈现怎样的 UI 状态
3. 为什么不建议在 ViewModel 处理异常?
3.1 破坏分层,增加耦合
如果在 ViewModel 中写这种代码:

那么:
- ViewModel 将直接依赖底层实现
- 网络库、数据源一旦更换,ViewModel 就需要修改
- 异常处理逻辑分散在多个 ViewModel 中,难以复用
而这些本应是 Repository / UseCase 的职责。
3.2 错误处理难以统一
当多个 ViewModel 各自处理异常时,往往会出现:
- 相同错误在不同页面展示方式不一致
- 重复的异常处理逻辑到处复制
- 想统一策略(例如:失败统一提示)成本极高
将异常处理集中在 UseCase / Repository,可以保证:
- 策略统一
- 行为可控
- 上层逻辑极度简单
4. 建议的整体模式(总结)
可以用一句话概括:
UseCase / Repository 负责"把异常变成结果"; ViewModel 负责"把结果变成 UI 状态"。
UseCase / Repository:
-
捕获所有外部系统异常
-
处理日志、监控、重试等技术细节
-
将结果统一转换为:
Success(data)Error
ViewModel:
- 不接触任何异常对象
- 不做异常分类
- 只根据结果更新 UI
5. 结语
只要异常已经在 UseCase / Repository 层被处理并转换成结果:
- ViewModel 就不应该再关心异常本身
- 它的世界里只剩下:成功或失败
这样的设计带来的好处是:
- 分层清晰,职责单一
- ViewModel 更容易测试
- 代码更稳定、更容易维护
如果你现在的项目中,ViewModel 里还有大量 try/catch,可以从一两个接口开始,先把异常下移到 UseCase / Repository,逐步过渡到ViewModel 只消费结果的模式。