StreamProvider Riverpod зависает при загрузке при чтении окна Hive | Флаттер

Я пытаюсь передать данные пользователей, которые я сохранил, в поле под названием «пользователи» с помощью 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)
);

Проблема с этой реализацией заключается в том, что она всегда показывает желтый экран, что означает, что она не загружается. Любые идеи?


person Florian Leeser    schedule 09.01.2021    source источник
comment
Достигнута ли доходность? И если да, то карта называется? Возможно, в ваш поток ничего не добавляется   -  person Rémi Rousselet    schedule 09.01.2021
comment
@ RémiRousselet Я удалил карту и получил только чек data==null ?. Такое же поведение. Как я могу проверить вашу доходность?   -  person Florian Leeser    schedule 09.01.2021


Ответы (1)


Привет, я думаю, у меня есть какое-то решение для вас, насколько я понимаю, метод просмотра Box будет пуст при первом запуске, не имеет значения, есть ли что-то в коробке, потому что часы срабатывают только тогда, когда есть изменение, так как в тот момент, когда он начинает прослушивание, поэтому он будет в состоянии загрузки, пока вы не измените значение ключа 0 где-нибудь в своем приложении.

Я не очень-то фанат такого поведения, и было бы лучше, если бы метод часов возвращал исходные данные с первого раза.

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

Таким образом, он покажет значение, сохраненное в вашем поле в начале вашего приложения, а затем изменение событий, связанных с этим ключом.

person EdwynZN    schedule 09.01.2021
comment
Спасибо! Это дает мне хорошее объяснение того, почему это не работает, но не то, как реализовать решение. - person Florian Leeser; 09.01.2021
comment
попробуйте мое обновление и скажите, поможет ли оно вам - person EdwynZN; 09.01.2021
comment
Проблема с вашей обновленной реализацией заключается в следующем: если в базе данных нет пользователя, поток все время будет выдавать нулевое значение, что означает: Цикл загрузки. Я решу эту проблему, создав пустой объект User, если значение потока равно нулю. Я полагаю, что при таком подходе null должен выдаваться только тогда, когда ProviderReader действительно загружается. - person Florian Leeser; 09.01.2021
comment
userBox.get (0, defaultValue: User ()); или какой-то фабричный конструктор User (например, User.empty ()) - person EdwynZN; 09.01.2021
comment
Ты был прав! Оно работает! Это очень простой способ решения проблемы с исходным нулевым значением. Тем не менее, ему нужен какой-то другой тип данных (например, пустой объект User). - person Florian Leeser; 10.01.2021
comment
это всегда будет зависеть от того, что вам нужно показать в первую очередь, когда в поле нет сохраненного значения; если это помогло вам решить проблему, теперь вы можете принять ответ - person EdwynZN; 10.01.2021