likes
comments
collection
share

Flutter - 如何使用 Flutter Riverpod Generator 自动生成 Provider

作者站长头像
站长
· 阅读数 3

Riverpod 是 Flutter 中一个强大的状态管理 & 数据绑定框架,它提供了很多种类的 Provider:

  • 访问代码中的依赖项或配置(Provider)
  • 缓存网络请求或其他场景下的异步数据(FutureProvider、StreamProvider)
  • 管理本地状态(StateProvider、StateNotifierProvier)

但是手写众多的 Providers 很麻烦且容易出错,并且有时候很难选择使用哪个 Provider。

所以今后可以不再需要手写麻烦的代码。简单的使用 @riverpod,让 build_runner 来帮助你快速生成 Providers。

这就是 riverpod_generator 包的用途所在。

Flutter - 如何使用 Flutter Riverpod Generator 自动生成 Provider

手写 Provider

我们先来回顾下,如何手写 Provider。场景如下:

我们有一个类 ImageRepository 负责管理图片数据,类中有两个方法 getImageCountgetImageSize 分别获取图片数量和图片尺寸。

传统的写法如下:

Flutter - 如何使用 Flutter Riverpod Generator 自动生成 Provider

如果遇到更麻烦一点儿的 StateNotifierProvider

Flutter - 如何使用 Flutter Riverpod Generator 自动生成 Provider

虽然静态分析能帮我们计算出类型,但代码可读性并不是很好。

@riverpod

入门

  1. 我们需要将必要的包,添加到 pubspec.yaml 里:
dependencies: 
  flutter_riverpod:      
  riverpod_annotation: 
dev_dependencies: 
  build_runner: 
  riverpod_generator:

2. 获取包:

flutter pub get

3. 以 watch 的方式启动代码生成器:

flutter pub run build_runner watch -d

-d 参数是可选的,同 --delete-conflicting-outputs

这将监视我们项目中所有的 Dart 文件,并在我们进行更改时自动生成代码。

使用

使用分为4步:

  1. 导入 riverpod_annotation 包;
  2. 添加 part 文件;
  3. 使用 @riverpod;
  4. 更新内容。

Flutter - 如何使用 Flutter Riverpod Generator 自动生成 Provider 一旦我们保存文件,build_runner 就开始工作并在同一文件夹下生成 by_annotation_providers.g.dart 文件。

Flutter - 如何使用 Flutter Riverpod Generator 自动生成 Provider 打开我们生成的文件,就能看到如下内容: Flutter - 如何使用 Flutter Riverpod Generator 自动生成 Provider 我们可以看到生成了 imageRepositoryProvider 以便于我们使用,还定义了类型为 AutoDisposeProviderRef<ImageRepository>ImageRepositoryRef

复杂一点的情况同样很简单。相信我,你一旦稍微熟悉了使用,上手之后会觉得太轻松不过了。使用 @riverpod 将上面的改造为下面: Flutter - 如何使用 Flutter Riverpod Generator 自动生成 Provider

在 Widget 中可以这样使用: Flutter - 如何使用 Flutter Riverpod Generator 自动生成 Provider 最关键的是这行:

final imageSizeAsync = ref.watch(imageSizeProvider(imageId: imageId)); 如我们所见,imageId 是命名参数,我们已经这样定义了它: Flutter - 如何使用 Flutter Riverpod Generator 自动生成 Provider 这意味着我们不再局限于定义一个只有一个参数的 FamilyProvider。事实上,我们甚至不在乎我们是否使用 family。我们所做的只是用一个 ref 对象和我们喜欢的任意数量参数来定义的函数,riverpod_generator负责其他的工作。

生成的 familes 是怎么实现的?

我们来看一下 imageSizeProvider 是怎么实现的:

Flutter - 如何使用 Flutter Riverpod Generator 自动生成 Provider 这里使用了callable classes,Dart 语言的一个简洁特性。它允许我们调用 imageSizeProvider(imageId: imageId) 而不是 imageSizeProvider.call(imageId: imageId)

支持 StreamProvider

如果我们有一个方法返回一个 Stream,我们同样能生成对应的 Provider:

Flutter - 如何使用 Flutter Riverpod Generator 自动生成 Provider

StateProvider 和 StateNotifierProvider

autoDispose 和 keepAlive

常见的需求就是,在不再使用时销毁 Provider 的状态。旧的语法是通过 autoDispose 来实现的。如果使用新的 @riverpodautoDispose 现在默认启用,并且重命名为 keepAlive

这意味着如下两段代码是等价的:

Flutter - 如何使用 Flutter Riverpod Generator 自动生成 Provider

Flutter - 如何使用 Flutter Riverpod Generator 自动生成 Provider 所以当我们把 keepAlive 设置为 true,Provider 会保持活跃。

优缺点

优点

自动生成正确类型的 Provider

最大的优点是我们不需要弄清楚我们需要哪种 Provider,因为 code generator 会自动从函数签名中找到他们。新的 @riverpod 还可以声明带有一个或多个参数的复杂 Provider,另一个好处是生成的代码为每一个专有类型创建了一个 ref 对象,这可以很容易从函数名中推断出来:

  • imageRepository() -> imageRepositoryProviderImageRepositoryRef

这使得运行时类型错误的可能性降低,因为如果我们不使用正确的类型,我们的代码将无法编译。

默认 autoDispose

使用新语法,所有生成的 Providers 都默认使用 autoDispose。 这是一个明智的选择,因为我们不应该保留不再使用的 Provider 的状态。

Provider 的热重载

当你在修改 provider 的代码时候,Riverpod 将会重新执行该 provider 并且只会执行该 provider。

缺点

代码生成

所有的缺点都归结为:Code Generation

即使最简单的 Provider 也会在单独的 .g.dart 文件中生成数十行代码,这会减慢构建过程并且会使项目因为额外的文件变得混乱。而且如果将 .g.dart 文件添加到版本控制中,将在每次更改的时候都会展示在 Pull Request 上。如果不想这样,我们可以把 .g.dart 文件添加到 。gitignore 文件中。

而且由于在开发过程中一直需要 flutter pub run build_runner watch,如果是很大的项目使用 build_runner,则需要更强大的电脑。

并不支持所有的 Provider

刚才也提到了,只支持以下:

  1. Provider
  2. FutureProvider
  3. StreamProvider
  4. NotifierProvider
  5. AsyncNotifierProvider

虽然不支持 StateProviderStateNotifierProvider,但可以使用 NotifierAsyncNotifier 来替换他们。

结论

正如我们所见,riverpod_generator 包提供了很多功能,以下是使用它的几个原因:

  • 自动生成正确类型的 Provider
  • 更容易创建带参数的 Provider,克服旧的 family 修饰符语法的局限性
  • 提高了类型安全性并减少了运行时的类型错误
  • 默认 autoDispose

但是,不支持某些旧的 Provider类型。

而且由于依赖于代码生成,因此您必须:

  • 处理项目中额外的自动生成的文件
  • 决定是否应该将生成的文件添加到 git

总的来说,最显著的优势是提高了开发人员的生产力。新语法意味着你又要重新学习和使用一个更小更熟悉的 API。这使得 Riverpod 更容易被旧 API 搞糊涂的开发者所接受。


要不要试试呢?😎