适合谁看

  • 正在给 Flutter 项目选状态管理方案的人

  • 想理解 Riverpod 为什么适合中型内容应用的人

  • 已经在项目里看到不少 Provider,但还没理清整体思路的人

问题背景

状态管理方案是否合适,关键看项目里到底有哪些状态:

  • 全局状态还是页面状态

  • 短生命周期还是长生命周期

  • 同步状态还是异步状态

  • 纯 UI 状态还是业务状态

如果项目里只有少量页面和简单交互,很多方案都能工作。
但一旦状态类型开始变多,选择就会变得更重要。

项目中的真实场景

食界探味当前和 Riverpod 相关的真实代码主要在:

  • app/lib/main.dart

  • app/lib/app.dart

  • app/lib/features/auth/providers/auth_provider.dart

  • app/lib/features/explore/providers/explore_provider.dart

  • app/lib/features/search/providers/search_provider.dart

  • app/lib/features/collection/providers/collection_provider.dart

  • app/lib/features/wish_box/providers/wish_provider.dart

  • app/lib/core/ai/ai_explore_coordinator.dart

从这些文件就能看出,这个项目的状态不是集中在一个模块里,而是分布在多个业务域中。
而且它还不是一个普通 Flutter 应用,因为状态最终还要承接来自 HarmonyOS 的系统入口和平台事件,例如:

  • app/lib/core/platform/intent_navigation_channel.dart

  • app/lib/core/platform/anti_peep_protection_channel.dart

  • app/ohos/entry/src/main/ets/entryability/EntryAbility.ets

核心实现

这篇如果只说“Provider 很多,所以适合 Riverpod”,其实还是不够。
真正的判断应该回到两个问题:

  • 项目里到底有哪些不同类型的状态

  • 这些状态是不是还要和 HarmonyOS 的系统入口、平台回调一起协作

一、这个项目里有很多“异步业务状态”,而且分布在不同业务域

例如:

  • 鉴权登录状态

  • 探索首页数据加载状态

  • 搜索请求状态

  • 收藏和已吃过状态

  • 愿望单提交状态

  • AI 会话状态

这些状态都不是简单的本地布尔值,而是带有:

  • 加载中

  • 成功

  • 失败

  • 刷新

等阶段变化。
Riverpod 在这里真正的价值,不是“能存值”,而是能比较自然地表达:

  • 一个状态是不是异步状态

  • 这个状态属于哪个业务域

  • 谁依赖谁

  • 生命周期要不要回收

例如当前项目里就已经有比较清楚的分域:

  • authProvider 管登录态

  • exploreProvider 管首页聚合数据

  • searchProvider 管搜索状态和翻页

  • wishHomeProviderwishSubmitProvider 管许愿箱首页与表单提交流程

这种分法和 Riverpod 的思路是匹配的。

二、状态天然按功能分散,而不是集中成一个超级 Store

当前项目的 Provider 分布方式很清楚:

  • 每个 feature 有自己的 providers

  • AI 在 core/ai

  • 全局路由和配置在 app.dartcore/config

这和 Riverpod“按依赖组织,而不是按全局仓库组织”的思路很匹配。
换句话说,当前项目不是那种“所有状态都想塞进一个大对象”的结构,而是:

  • 每个 feature 管自己的状态

  • repository 通过 Provider 注入

  • 页面只 watch 自己真正关心的状态切片

这点在鸿蒙 Flutter 项目里尤其重要。
因为系统入口、平台事件、AI 会话这些状态如果也被硬塞进同一个超级 Store,后面会很难控制边界。

三、很多状态本身带生命周期,而鸿蒙场景会把生命周期问题放大

例如:

  • 搜索结果离开页面后可以释放

  • AI 会话页面离开后可以回收

  • 提交表单的临时状态不需要全局常驻

项目里已经大量使用:

  • StateNotifierProvider.autoDispose

这说明它不只是想“保存状态”,而是也在关心状态何时销毁。

而到了鸿蒙项目里,这件事会更关键。
因为有些状态并不是只受 Flutter 页面生命周期影响,还会受系统入口和原生事件影响,例如:

  • Intents Kit 可能在应用冷启动时带进 pageId

  • 防窥状态可能在页面已经显示时由原生侧异步推回

  • 语音识别和 TTS 会把页面状态从 idle 拉到 listening / speaking

如果状态层本身没有分域、没有生命周期意识,Flutter 侧就很难优雅接住这些平台侧回调。

四、Riverpod 更适合把依赖显式写出来,而不是靠隐式单例串项目

routerProviderauthProvideraiExploreCoordinatorProvider 这类对象,都更适合通过 Provider 显式暴露依赖关系,而不是通过隐式单例到处拿。

这对鸿蒙项目还有一个额外好处:

  • Flutter 侧路由、业务状态、平台边界对象可以保持清楚分层

例如:

  • routerProvider 只管路由对象

  • authProvider 只管登录态

  • IntentNavigationChannel 负责平台入口转路由

  • AntiPeepProtectionChannel 负责平台事件转页面状态

Riverpod 并不会替你处理所有平台问题,但它能让你把“谁管什么”写得更清楚。

五、这个项目适合 Riverpod,还有一个常被忽略的原因:Flutter 状态要承接 HarmonyOS 平台回调

很多 Flutter 项目只讨论页面状态;但食界探味不是这样。
它至少已经有三类明显来自平台侧的输入:

  1. EntryAbilityInsightIntentExecutorImpl 带进来的系统直达参数

  2. IntentNavigationChannel 在 Flutter 侧消费的 pending navigation

  3. AntiPeepProtectionChannel 推回来的可见性事件

这意味着 Flutter 状态层不能只想着:

  • 页面按钮点了之后怎么改状态

还得能接住:

  • 系统从外面打进来的状态变化

Riverpod 在这里的适配点就在于:

  • 业务状态仍然按 feature 管

  • 路由和平台边界可以单独暴露

  • 页面可以只 watch 自己需要的状态,而不用被整套平台逻辑污染

关键代码位置

  • app/lib/main.dart

  • app/lib/app.dart

  • app/lib/features/auth/providers/auth_provider.dart

  • app/lib/features/explore/providers/explore_provider.dart

  • app/lib/features/search/providers/search_provider.dart

  • app/lib/features/collection/providers/collection_provider.dart

  • app/lib/features/wish_box/providers/wish_provider.dart

  • app/lib/core/ai/ai_explore_coordinator.dart

鸿蒙侧实现

这一篇虽然重点在 Flutter 状态层,但它和鸿蒙其实有非常直接的关系。
对 HarmonyOS Flutter 项目来说,Flutter 侧状态管理越清晰,越容易承接来自:

  • Intent 导航

  • 语音识别

  • 防窥事件

这些平台侧回调。

当前项目里最值得注意的是:

  • 原生层并没有直接去改 Flutter 页面

  • 它只是把入口参数或事件推到边界层

  • 真正把这些变化吸收到页面里的,仍然是 Flutter 状态组织方式

也就是说,Riverpod 在这里不是离鸿蒙很远,反而是在帮 Flutter 层接住鸿蒙。

Flutter 侧实现

当前项目已经体现出几条比较典型的 Riverpod 用法:

  • 全局用 ProviderScope

  • 功能模块用 StateNotifierProvider

  • 临时状态优先 autoDispose

  • 路由和服务也可以通过 Provider 暴露

这是一种比较稳的中型应用组织方式。
如果再结合鸿蒙相关代码一起看,会更清楚:

  • ProviderScope 负责把状态系统立起来

  • GoRouter 通过 Provider 暴露

  • 平台边界对象负责接住原生输入

  • feature provider 负责把这些输入变成页面真正可消费的状态

常见坑

  • 所有状态都放进一个超大 Provider

  • 页面临时状态不回收,导致内存和逻辑膨胀

  • 把服务对象、路由对象、业务状态对象混在一起

  • 只用 Riverpod 保存值,却不利用它的依赖管理能力

  • 平台回调直接改页面局部状态,没有经过统一状态层

  • 为了接鸿蒙能力,把原生事件逻辑直接散落到多个页面里

可复用模板

final searchProvider =
    StateNotifierProvider<SearchNotifier, SearchState>((ref) {
  return SearchNotifier(ref);
});
业务状态按 feature 拆
平台边界单独收在 core/platform
路由对象单独暴露
系统入口和平台事件最终回到状态层消费

本篇总结

  • 食界探味适合 Riverpod,不是因为它流行,而是因为项目状态类型本身很多,而且来源不只在页面内部

  • Riverpod 在这里真正解决的是依赖显式化、状态分域、生命周期管理,以及对 HarmonyOS 平台输入的承接

  • 对这种带 AI、带平台能力、带系统直达入口的鸿蒙 Flutter 项目来说,这个选择是合理的

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐