【问题标题】:Riverpod's StreamProvider stuck in loading when reading Hive's box | FlutterRiverpod 的 StreamProvider 在读取 Hive 的盒子时卡在加载中 |扑
【发布时间】:2021-04-15 01:28:59
【问题描述】:

我正在尝试使用 Hive 将我保存的用户数据流式传输到一个名为“用户”的框中。这是为了显示基于用户提供的信息的屏幕。目前,该框不包含任何数据,因此我希望以下代码显示蓝屏。否则它应该是绿色或紫色。我必须知道读完的值,这样我才能知道返回的值null是数据还没有加载还是用户框是空的。

我正在使用 Riverpod 进行状态管理和这种方法。

我实现了以下两个提供者

final localUserBoxFutureProvider = FutureProvider<Box>((ref) async {
  final usersBox = await Hive.openBox('users');
  return usersBox;
});

final localUserStreamProvider = StreamProvider<User>((ref) async* {
  final usersBox = await ref.watch(localUserBoxFutureProvider.future);
  yield* usersBox.watch(key: 0).map((boxEvent) => boxEvent as User);
});

并希望像这样使用它们:

final localUserStream = watch(localUserStreamProvider);

return localUserStream.when(
  data: (data) => data == null ? Container(color: Colors.blue) : data.isEmailVerified ? Container(color: Colors.green) : Container(color: Colors.purple), 
  loading: () => Container(color: Colors.yellow), 
  error: (e, s) => Container(color: Colors.red)
);

这个实现的问题是它总是显示一个黄色的屏幕,这意味着它卡在加载中。有什么想法吗?

【问题讨论】:

  • “产量”达到了吗?如果是这样,是否调用了“地图”?您的信息流中可能没有推送任何内容
  • @RémiRousselet 我删除了“地图”,然后只检查了data==null ?。相同的行为。我如何检查您的“产量”部分?

标签: flutter provider riverpod flutter-hive


【解决方案1】:

嘿,我想我有一些解决方案,据我了解 Box 的 watch 方法在第一次运行时将为空,盒子是否有东西并不重要,因为 watch 只有在有时才会触发从它开始监听的那一刻起就发生了变化,因此它将处于加载状态,直到您在应用中的某处更改键 0 值。

我不是很喜欢这种行为,如果 watch 方法第一次返回初始数据会更好

final localUserStream = watch(localUserStreamProvider);

return localUserStream.when(
  data: (data) => data == null ? Container(color: Colors.blue) : data.isEmailVerified ? Container(color: Colors.green) : Container(color: Colors.purple), 
  loading: () => TextButton(
    onPressed: () async {
       final box = await watch(localUserBoxFutureProvider.future);
       await box.put(0, User()) // this is just an example that when you tap the button the stream actually change to data
    },
    child: Text('Update me'),
  ), 
  error: (e, s) => Container(color: Colors.red)
);

更新

这可能有点棘手(我还没有测试过),但您可以在 StreamProvider 中流式传输初始值

final localUserStreamProvider = StreamProvider<User>((ref) async* {
  final usersBox = await ref.watch(localUserBoxFutureProvider.future);
  yield* Stream.value(userBox.get(0, defaultValue: User())); //or getAt(0)
  yield* usersBox.watch(key: 0).map((boxEvent) => boxEvent as User);
});

这样,它会在应用开始时显示保存在框中的值,然后显示与该键相关的事件的更改

【讨论】:

  • 谢谢!这给了我一个很好的解释为什么它不起作用,而不是如何实施解决方案。
  • 试试我的更新,告诉我它是否对你有帮助
  • 你更新实现的问题如下:如果数据库中没有用户,流将一直产生一个空值,这意味着:加载周期。如果流值为空,我将通过产生一个空的用户对象来解决这个问题。使用这种方法,我猜只有在 ProviderReader 真正“加载”时才应该发出 null 。
  • userBox.get(0, defaultValue: User());或用户的一些工厂构造函数(例如 User.empty())
  • 你是对的!有用!对于“初始空问题”,这是一个非常干净的解决方法。然而,它需要某种不同的数据类型(例如空的用户对象)。
猜你喜欢
  • 2020-11-04
  • 1970-01-01
  • 2021-10-20
  • 2021-05-22
  • 2022-11-16
  • 2021-03-19
  • 2022-12-04
  • 2014-11-16
  • 2021-10-03
相关资源
最近更新 更多