Flutter 中的状态管理

状态管理是 Flutter 中一个非常火热的话题。随着应用程序规模的逐渐扩大,业务逻辑也随之变得复杂,比如在用户登陆后,应用各个页面的状态都需要得到及时的更新。传统的 UI 和业务逻辑纠缠在一起的做法,使得代码变得复杂冗余,也为各种潜在 bug 埋下了伏笔。因此将状态和业务逻辑分离,统一地对状态进行管理,使得编程实现和应用结构都更加清晰简明。在 Flutter 的官方文档中也对状态管理进行了讨论,列举了 Flutter 中几种常见的状态管理的框架。

ScopedModel

scoped_model 是最为简单的 Flutter 状态管理框架,它提供了三个类:

  1. Model:所有我们自定义的模型都需要继承自这个 Model。当 Model 的状态发生改变时,需要在 Model 中通过notifyListeners()方法来通知所有的 listener。
  2. ScopedModel:当把一个 Widget 和 Model 包裹在一个 ScopedModel 中时,这个 Widget 的所有子 Widget 都可以访问到这个 Model。
  3. ScopedModelDescendant:用 ScopedModel 包裹的 Widget 的子 Widget 都应该用ScopedModelDescendant 来包裹,这样这些子 Widget 就可以获得第一步中的 Model,并且在 Model 状态发生改变后自动重建。

一个完整的例子可以在 Github 上进行查看。

Redux

Redux 原本是用于前端开发的状态管理框架,但也可以和 Flutter 很好地结合起来。在 Redux 中,有四大重要的概念:State、Action、Reducer 以及 Store。State 就是应用程序中的状态,State 会反映在 UI 上。Action 是应用程序中的动作,该动作会引起 State 的改变。而 Reducer 则是用来处理 Action 的,它接受一个 Action 和一个 State,并根据 Action 的内容返回一个新的 State。Store 既是一个状态容器,也是一个动作派发者,应用程序当前的状态可以通过 store.getState来获得,新的 Action 则通过 store.dispatch(action)派发给 Reducer 进行处理。

在 Flutter 生态中,Redux 包提供了对StoreMiddlewareReducer等的支持,而 flutter_redux 插件则提供了StoreProviderStoreConnectorStoreBuilder几个让使用 Redux 更加便利的类,让我们可以更容易地在 Flutter Widget 中获得 Store 及其相关状态,以及进行 Action 的派发。

StoreProvider的作用是将 Store 传入 App 中,这样整个 App 内的 Widget 都可以通过 StoreConnector或者StoreBuilder 来获得 Store:

StoreConnectorStoreBuilder 的作用都是让子 Widget 获得 Store,并通过 Store.getState 方法获得 State,然后通过 State 来设置子 Widget 的样式。不同的是,StoreConnector在使用时需要传入一个 ViewModel 类型,并且需要编写 convert 方法,来确定如何从 Store 创建 ViewModel,而StoreBuilder则是直接使用就可以了。两者适用于不同的场景:当State结构复杂,而当前的 Widget 只需要 State 中的某些属性时,那么可以使用StoreConnector,并将需要用到的这些属性映射到一个 ViewModel 里,这样所需的属性直接从 ViewModel 里取就可以了,避免了类似于store.state.weatherState.weather.condition这样复杂冗长的取值过程。而当State比较简单时,就可以直接使用StoreBuilder

如下是使用StoreConnector的一段示例:

当使用StoreBuilder来构建时,其写法是非常类似的:

Bloc

Bloc(Business Logic Component)是由来自谷歌的 Paolo Soares 和 Cong Hui 设计的设计模式,最早在 2018 年的 DartConf 上被展示。这个模式的设计目的是将数据的展示和业务逻辑分离开,使得测试和重用变得更加容易。

Bloc Pattern

Flutter 中的 blocflutter_bloc 插件让使用 Bloc 和使用 Redux 来进行状态管理有相似的流程,因此对于熟悉 Redux 的人来说,可以很快速地切换到 Bloc 上。

flutter_bloc 中提供了如下几个 Widget:

  1. BlocBuilder
  2. BlocProvider和BlocProviderTree
  3. BlocListener和BlocListenerTree

BlocProviderStoreProvider 的作用相同,当用 BlocProvider 来构建一个 Widget 后,它的所有子 Widget 也可以取到其中的 bloc。BlocBuilder 则类似于 Flutter 中的 StreamBuilder,它有一个接受 bloc 的参数,还有一个接受 State 的 builder 函数,当 State 发生变化时,build 函数会自动被调用。BlocListener 与 BlocBuilder 也很类似, 有一个接受 bloc 的参数,还有一个接受 State 的 listener 函数,当 State 发生变化时,listener 函数会被调用。

在子 Widget 中,可以通过 BlocProvider 的 of 方法来获得 bloc:

在上面提到的 bloc,与 Redux 的 Store 作用类似。bloc 需要继承自 Bloc 类,并且重载mapEventToState 方法,该方法类似于 Redux 中的 Reducer,根据当前的 State 与 Event 来确定下一步的 State。Event 就类似于 Redux 中的 Action。bloc 中也有 dispatch 方法,参数是一个 Event:

为了比较 Redux 和 Bloc 的不同,我在学习了 Bloc 文档中提供的 Weather 应用编写教程后,将它用 Redux 重新实现,所有代码已经上传到 Github 上,地址分别是[flutter_weather_bloc](https://github.com/tamarous/flutter_weather_bloc)[flutter_weather_redux](https://github.com/tamarous/flutter_weather_redux)

参考资料

  1. 让我来帮你理解和选择Flutter状态管理方案
  2. Redux 中文文档
  3. Flutter完整开发实战详解(十二、全面深入理解状态管理设计)
  4. Flutter Weather Tutorial

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据