Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
599 views
in Technique[技术] by (71.8m points)

provider - Riverpod's StreamProvider stuck in loading when reading Hive's box | Flutter

I am trying to stream the users data that I saved into a box called 'users' with Hive. This is for showing a screen based on the information provided from the user. For now, the box contains no data, so I expect the following code to show a blue screen. Otherwise it should be green or purple. It is mandatory for me to know when reading the value finished, so that I know wether the returned value null means the data did not load yet or the users box is empty.

I am using Riverpod for state management and this approach.

I implemented the following two providers

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);
});

and would like to use them like something like this:

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)
);

The problem with this implementation is that it always shows a yellow screen, meaning its stuck in loading. Any ideas?

question from:https://stackoverflow.com/questions/65644261/riverpods-streamprovider-stuck-in-loading-when-reading-hives-box-flutter

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Hey I think I have some solution for you, as far as I understand the watch method of a Box will be empty the first time it runs, it doesn't matter if the box has something because watch only fires when there is a change since the moment it starts listening so it will be in loading state until you change the key 0 value somewhere in your app.

I'm not really a fan of this behavior and it would be better if the watch method returns the initial data the first time

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)
);

UPDATE

This can be a bit tricky (and I haven't tested it) but you could stream an initial value in your 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);
});

This way it will show the value saved in your box at the beggining of your app, and afterwards the change of events related with that key


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...