VGV:我们为什么使用flutter_bloc进行状态管理

Flutter项目组的合作开发商VGV,在近期发表博客文章why-we-use-flutter-bloc,对他们公司为什么使用flutter_bloc进行说明。我觉得这篇文章写的不错,结合我个人对Bloc的实践感受,在此做个简单的归纳式翻译。


状态管理是Flutter开发中不可回避的争议话题,社区中几乎每周都会出现类似哪个状态管理库最好的讨论。这个现象很正常,因为状态管理方案直接决定了你应用的整体架构,这是个不小的决定。我们的看法是,最适合的就是最好的。在setState, redux, mobX, flutter_bloc等众多选择中,最适合我们的就是flutter_bloc。我们将解释选择flutter_bloc的原因,同时也对bloc的两个常见误解进行解答。

选择flutter_bloc的原因

可预测

产品开发最大的挑战之一,是在任意时刻了解应用的真实状态。

flutter_bloc将应用状态抽象成多个小型状态机,状态机接受事件(event)输入,然后生成状态(state)。举个例子:点击打开外卖app,出现加载进度条表明正在通过网络拉取数据,如果成功将显示餐馆列表,失败则显示错误信息。

将事件和状态抽象出来后,业务逻辑非常清晰,应用所处何种状态一目了然。以下是示意代码:

@override
Stream mapEventsToState(FavoriteRestaurantEvent event) async* {
  if (event is AppOpened) { // 打开App事件
    yield FavoriteRestaurantsLoadInProgress(); // 进入加载中状态
    try {
      final restaurants = await restaurantsRepository.fetchFavoriteRestaurants(); // 拉取数据
      yield FavoriteRestaurantsSuccess(restaurants); // 转为获取成功状态
    } catch(_) {
      yield FavoriteRestaurantsFailure(); // 进入失败状态
    }
  }
}

“简单”

所有的UI编程都是类似的,大部分时间UI都处于空闲状态,等待客户交互或系统事件,然后执行动作提供数据。传统的解决方法是使用 callbacks, Rx, Streams 等API,虽然可行但后期复杂度会越来越高。

flutter_bloc对Dart的Stream进行了封装,开发者不需要处理订阅、生命周期等等,只需要关注两件事:接受的事件和生成的状态(也就是状态机的输入和输出),也就使开发变得更加“简单”。

易于测试

flutter_bloc自带bloc_test,即开即用,业务逻辑的测试变得简单

blocTest(
  'emits [1] when CounterEvent.increment is added',
  build: () => counterBloc,
  act: (bloc) => bloc.add(CounterEvent.increment), // 发送加1事件
  expect: () => [1], // 预期结果为1
);

blocTest(
  'emits [-1] when CounterEvent.decrement is added',
  build: () => counterBloc,
  act: (bloc) => bloc.add(CounterEvent.decrement), // 发送减1事件
  expect: () => [-1], // 预期结果为-1
);

文档

flutter_bloc 以其详细的文档(提供多达 10 种语言的翻译,包含中文)、高质量教程(从简单的计数器项目到与 Firebase 的复杂集成)以及对 Angular Dart 的支持而闻名于社区。

  • 经典的示意图

使用者众多

从一个BMW的内部项目,逐步开源演变,在Github获得7k+的star,成为flutter社区的明星级项目,使用者众多,也进入了开发者最喜爱( Flutter Favorite)的项目之列。

对flutter_bloc的误解

误解1: Bloc 太复杂了

Flutter虽然自带了强大的状态管理方案即StatefulWidget的setState,但它在多个变量、事件及路由处理等复杂场景下,界面将出现不必要的重建(rebuild),且代码也变得难以阅读和维护。

通过flutter_bloc库的封装,你不需要熟悉掌握Stream或RxDart等复杂API。初期只需要了解bloc自身的API,以及BlocProvider、BlocBuilder等组件,而且官网还提供了非常详细的文档。根据我们的经验,一旦你入门了flutter_bloc,它将极大提升开发者的生产力和效率,因为它简单,而且需要学习的概念相对较少。

误解2: Bloc 有太多重复的样板代码

flutter_bloc需要你对事件和状态进行抽象,封装成不同的类。对比其他状态管理方案,这看起来是倒退,因为实现相同的功能竟需要写更多的代码!

虽然如此,但为事件和状态单独建模会带来非常大的好处:

  • 可以将它们封装为不可变(immutable)对象
  • 事件和状态以及它们的属性完全隔离

同时,bloc为 VS Code IntelliJ提供了插件,可以自动生成大部分重复性代码。 如果你是真的不希望面对那么多样板代码,你还可以使用cubit,它可以视作bloc的简化版本,它去掉了事件(event),你只要调用方法生成状态就好。


博客原文:

注:VGV即verygood.ventures是一家从2017年就开始提供Flutter开发服务的公司,是flutter_bloc作者所在的公司,也是Flutter项目组的合作开发商,2021 Google IO照相馆就是出自他们之手。