欢迎加入开源鸿蒙跨平台社区:
https://openharmonycrossplatform.csdn.net

Flutter Provider 在 OpenHarmony 项目中的状态管理实践

前言

最近这段时间一直在做 Flutter for OpenHarmony 的适配项目,随着页面越来越多,我发现一个问题开始变得明显:

页面状态越来越不好管理了。

一开始项目比较简单的时候,其实直接:


setState()

也能跑。

但后面随着:

  • 首页
  • 用户中心
  • 商品详情
  • 购物车
  • 消息页

这些模块逐渐加进来之后,状态开始变乱。

最明显的问题包括:

  • 页面之间数据同步困难
  • 多层 Widget 传参
  • 页面刷新范围过大
  • rebuild 过于频繁
  • 代码越来越难维护

后来我把项目状态管理统一迁移到了 Provider,整体结构清晰了不少,而且在 OpenHarmony 真机上的页面稳定性也好了很多。

这篇文章主要记录一下这次状态管理改造过程。


一、为什么最后选择 Provider

Flutter 状态管理方案其实很多。

常见的:

方案 特点
setState 简单
Provider 官方推荐
GetX 上手快
Riverpod 功能强
Bloc 适合大型项目

我最后选 Provider 的原因比较现实:

  • 官方生态成熟
  • 学习成本低
  • Flutter 社区资料多
  • 适合中型项目
  • 对现有项目改动不算太大

而且 Flutter 官方很多示例本身也在用 Provider。

对于 OpenHarmony 项目来说:

稳定其实比“炫技”更重要。


二、项目里最开始的问题

先说一下我之前的代码结构。


页面层层传参

比如首页用户信息:


HomePage(
  user: user,
)

然后:


BodyWidget(
  user: user,
)

接着:


InfoCard(
  user: user,
)

参数一路往下传。

页面层级一多之后:

代码非常难维护。


setState 到处都是

例如:


setState(() {
  cartCount++;
});

刚开始问题不大。

但后面:

购物车、消息数、用户信息

这些全局状态越来越多。

整个页面会开始频繁 rebuild。


三、接入 Provider

1. 添加依赖


dependencies:
  provider: ^6.1.2

执行:


flutter pub get

四、创建状态类

这里我先拿用户信息举例。


UserProvider


class UserProvider extends ChangeNotifier {

  String name = "";

  void updateName(String value) {

    name = value;

    notifyListeners();
  }
}

核心其实就两部分:

  • 数据
  • notifyListeners()

五、全局注入 Provider

在项目入口:


void main() {

  runApp(

    MultiProvider(

      providers: [

        ChangeNotifierProvider(
          create: (_) => UserProvider(),
        ),

      ],

      child: const MyApp(),
    ),
  );
}

这样后面页面里就能直接获取状态。


六、页面读取状态

1. 最基础写法


final userProvider =
    Provider.of<UserProvider>(context);

读取:


Text(userProvider.name)

更新:


userProvider.updateName("Tom");

七、我在 OpenHarmony 项目里遇到的一个问题

这个问题我刚开始其实没太注意。


问题现象

页面频繁 rebuild。

例如:

修改购物车数量后:

整个首页都刷新了。

包括:

  • Banner
  • 列表
  • 用户信息

全部重新 build。

在鸿蒙设备上:

卡顿会比 Android 更明显一点。


原因

我当时直接:


Provider.of<UserProvider>(context)

默认:


listen: true

也就是说:

状态变化后整个 Widget 都会刷新。


八、后来的优化方案

1. 使用 Consumer

后来我改成:


Consumer<UserProvider>(
  builder: (_, provider, __) {

    return Text(provider.name);
  },
)

这样只有 Consumer 内部刷新。

效果会好很多。


2. 使用 Selector

后面进一步优化:


Selector<UserProvider, String>(
  selector: (_, provider) {
    return provider.name;
  },

  builder: (_, name, __) {
    return Text(name);
  },
)

这个优化在复杂页面里挺明显。

尤其 OpenHarmony 真机测试时:

rebuild 次数下降很多。


九、不要把所有状态都放一个 Provider

这个坑我后面踩得挺深。


错误结构


class AppProvider extends ChangeNotifier {

  UserModel user;

  List cartList;

  bool darkMode;

  int msgCount;
}

刚开始图方便。

结果后面:

任何一个状态变化。

整个页面树都在刷新。


后来的拆分方案


UserProvider
CartProvider
ThemeProvider
MessageProvider

每个模块单独管理。

后面维护会轻松很多。


十、Provider 和页面生命周期问题

这里有个我在鸿蒙设备上实际碰到的问题。


问题

页面 initState 里直接读取 Provider:


@override
void initState() {

  super.initState();

  final userProvider =
      Provider.of<UserProvider>(context);
}

直接报错:


dependOnInheritedWidgetOfExactType

正确方式


Provider.of<UserProvider>(
  context,
  listen: false,
)

或者:


WidgetsBinding.instance
    .addPostFrameCallback((_) {

});

这个问题 Flutter 本身就有。

但 OpenHarmony 调试时会更容易暴露。


十一、购物车模块的一个实际优化

购物车是我这次改造里变化最大的地方。


优化前

点击商品:


setState(() {
  cartCount++;
});

整个页面刷新。

列表明显掉帧。


优化后


context.read<CartProvider>()
    .addGoods(goods);

购物车角标:


Consumer<CartProvider>(
  builder: (_, provider, __) {

    return Text(
      provider.count.toString(),
    );
  },
)

最终:

只有角标刷新。

页面流畅很多。


十二、我的最终项目结构

后面项目里我基本统一成:


providers/
 ├── user_provider.dart
 ├── cart_provider.dart
 ├── theme_provider.dart
 └── message_provider.dart

业务层:


pages/
services/
models/
widgets/

整体会清晰很多。


十三、实际效果

改造前:

问题 表现
页面 rebuild 高频
状态同步 混乱
多层传参 严重
页面卡顿 存在

改造后:

项目 效果
页面刷新 更精准
代码结构 更清晰
页面流畅度 提升明显
状态维护 更容易

目前这个方案已经在 OpenHarmony 项目里稳定用了挺长时间。


十四、总结

这次做 Flutter Provider 状态管理改造,一个比较深的感受是:

Flutter 项目到后期,真正难维护的往往不是 UI。

而是状态。

尤其是跨平台项目:

如果状态管理混乱:

后面定位问题会非常痛苦。

Provider 虽然不是最“高级”的方案。

但:

  • 足够稳定
  • 学习成本低
  • 社区成熟
  • 很适合业务项目

对于 Flutter for OpenHarmony 这种场景,其实挺合适。

后面我也准备继续研究:

  • Riverpod 在 OpenHarmony 下的表现
  • Flutter 状态持久化
  • Provider + 网络层结合
  • 大型项目状态拆分方案

希望这篇文章能给正在做 Flutter for OpenHarmony 项目的同学一点参考。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐