Repository 方法设计:suspend 与 Flow 的决选择指南(以朋友圈为例)

932 阅读3分钟

在Repo接口定义中,常见两类函数:

  • suspend functions:返回单一结果
  • 普通函数返回 Flow:返回一个结果流

这两类函数在 Room DAO 等库中都有体现。例如 observeUsers() 返回 Flow,因为它是一个观察者,每次表变化都会发射新的用户列表。


一、通用原则

  • 使用 suspend:当函数只产生一个结果时,例如数据库查询或调用外部服务
  • 使用 Flow:当函数可能产生未知数量的结果时,例如 WebSocket 连接或数据库观察

不推荐在只期望一个结果的场景使用 Flow,原因包括:

  1. 语义误导Flow 暗示多个结果
  2. 复杂度更高suspend 更简单、可读性更好、易于调试

二、朋友圈发送场景 —— 使用 suspend

在发送朋友圈的业务中,很多操作都是一次性触发并返回结果,因此适合用 suspend

  • 发布朋友圈:用户点击"发送"后,等待结果返回
  • 删除朋友圈:一次性操作,执行后即结束
  • 点赞/取消点赞:触发后立即返回结果
  • 发表评论:提交后返回成功或失败

示例接口

image.png

三、朋友圈动态场景 —— 使用 Flow

朋友圈的另一类需求是实时动态更新,例如:

  • 朋友圈列表:新内容发布后,列表需要自动刷新
  • 特定朋友圈详情:点赞数、评论数随时变化
  • 新朋友圈通知:好友发布新动态时推送
  • 互动更新:点赞、评论的实时变化

示例接口

image.png

四、 ViewModel与状态管理

ViewModel 的可观察状态通常用 StateFlow 表示。 因此,API 暴露 Flow 会更容易消费,可以直接用 stateIn 转换为 StateFlow

  • 小型应用:用 Flow 到处都行,差别不大
  • 复杂领域模型:滥用 Flow 会成为负担,suspend 更简洁
  • 最佳实践:可以定义辅助函数,把 suspend 转换为 StateFlow,避免强行用 Flow everywhere (不要为了迎合 ViewModel 的需要而让数据层所有 API 都返回 Flow,而是保持数据层 API 的简洁性(使用挂起函数),然后在 ViewModel 层通过辅助函数将一次性操作的结果转换为 StateFlow)。

五、决策流程图

image.png

我总结了一个图,如下:

Copilot_20251212_175153.png

六、总结原则

特征suspendFlow
数据特性静态,一次性动态,持续变化
结果数量单次结果多个值序列
使用场景发送朋友圈、删除、点赞、评论列表更新、通知、互动变化
生命周期执行完即结束持续到取消收集

简单记忆

  • 操作像 动词(做某事,例如"发送朋友圈") → 用 suspend
  • 操作像 名词(观察某物,例如"朋友圈动态") → 用 Flow