#flutter #provider #flutter-provider
Вопрос:
Я создал простое дерево виджетов своего приложения в flutter, которое решает проблему.
Проблема в том, что когда я вызываю метод в своем SleepSessionData
классе, который является ChangeNotifier
классом, потребитель не увольняется.
Нет никаких проблем, если метод, содержащий notifyListeners()
, вызывается в одном и том же виджете, но когда это два родственных виджета, потребитель не обновляется, если setState
не вызывается a.
И изображение экрана для справки
Данные о сеансе сна расширяют определитель изменений
void updateSelectedPlaylists(List<String> selectedPlaylists) {
this.selectedPlaylists = selectedPlaylists;
notifyListeners();
_saveData();
}
ПлейлистСелекторВиджет
void selectedIndex(int index) {
...
context.read<SleepSessionData>().updateSelectedPlaylists(_selectedPlaylistIds);
setState(() {});
}
В моем SettingsWidget
я пробовал использовать как Consumer
виджет, так и watch()
метод и. Но это так, как notifyListeners()
не вызывает потребителя/наблюдателя. Если я запущу setState()
(инициируемое пользовательским вводом) значение из ChangeNotifier
обновлений.
Вот мой MultiProvider
в main.dart
child: MultiProvider(
providers: [
ChangeNotifierProvider<MySleepData>(create: (_) => MySleepData()),
ChangeNotifierProvider<DirectoryData>(create: (_) => DirectoryData()),
FutureProvider<UserData>(
create: (_) => LocalPersistence.getUserData(),
initialData: UserData()),
FutureProvider<SleepSessionData>(
create: (_) => LocalPersistence.getSleepSessionData(),
initialData: SleepSessionData(),
)
],
Комментарии:
1. Я бы предположил, что это потому, что вы используете
FutureProvider
для своегоSleepSessionData
, а неChangeNotifierProvider
для . В документации дляFutureProvider
говорится: «Принимает будущее и обновляет зависимых, когда будущее завершается». — таким образом, он обновляется только при обновлении в будущем, но не самой модели / класса. Я предлагаюChangeNotifierProvider
также использовать там и оценить вашу асинхроннуюgetSleepSessionData
функцию до этого2. @kounex Спасибо за ваш ответ! Но я не думаю, что в этом проблема. Поставщик и
notifyListeners()
работает нормально, если онread()
иwatch()
вызывается из одного и того же виджета. Но в данном случае это не так. Но я проверю это, просто чтобы быть уверенным!3. вы пробовали использовать
listen:false
?
Ответ №1:
Вы не должны заворачивать себя ChangeNotifier
FutureProvider
внутрь, чтобы он работал должным образом.
Когда вы заворачиваете ChangeNotifier
его внутрь FutureProvider
, это нарушает процесс добавления слушателей к ChangeNotifiers
каким-либо образом. Вы всегда получаете 0 слушателей при обертывании ChangeNotifier
FutureProvider
. (Вы можете проверить это, отладив и проверив listeners
свойство своего ChangeNotifier
экземпляра.) Вот почему при вызове notifyListeners()
виджеты не перенаправляются , так как они не прослушивают ваш ChangeNotifier
экземпляр.
Таким образом, решением вашей проблемы было бы:
- Использование
ChangeNotifier
вmain.dart
child: MultiProvider(
providers: [
ChangeNotifierProvider<MySleepData>(create: (_) => MySleepData()),
ChangeNotifierProvider<DirectoryData>(create: (_) => DirectoryData()),
ChangeNotifierProvider<UserData>(create: (_) => UserData()),
ChangeNotifierProvider<SleepSessionData>(create: (_) => SleepSessionData()),
],
- В
SessionSetupPage
, вы получаете данные из своего локального хранилища и загружаете изменения вSleepSessionData
loadData(SleepSessionData sessionData) async {
final data = await LocalPersistence.getData();
sessionData.setData(data);
}
Widget build(BuildContext context) {
loadData(context.read<SleepSessionData>());
// ..
}
- Тогда код в вашем
PlaylistSelector
иSettingsWidget
должен работать всякийnotifyListeners()
раз, когда вызывается, так как прослушиватели теперь связаны правильно.
поэтому, когда будущее завершится, оно перезапишет это значение
Однако это не совсем основная причина проблемы. Даже если мы создадим SleepSessionData
экземпляр заранее и вернем тот же экземпляр внутри FutureProvider
, проблема все равно сохранится.
Ответ №2:
У вас есть только то FutureProvider
, что содержит SleepSessionData
so, которое будет обновляться только один раз, когда будущее завершится. Если вы хотите, чтобы пользовательский интерфейс обновлялся в связи с изменениями результата в будущем, вам нужно прослушать эти изменения, например, с помощью a ChangeNotifierProvider
.
Кроме того, вы предоставляете FutureProvider
исходные данные с новым экземпляром вашего SleepSessionData
, поэтому, когда будущее завершится, оно перезапишет это значение, что означает, что любые действия, которые вы выполняете с исходным значением, будут отброшены.
Поэтому лучшим способом сделать это было бы не использовать a FutureProvider
, а использовать a ChangeNotifierProvider
и начать в будущем загружать данные в свой SleepSessionData
класс.