[Flutter]:notifyListeners 在其他屏幕或弹出窗口中不起作用
[Flutter]: notifyListeners not working from other screens or popups
我正在使用提供程序库进行状态管理,到目前为止一切正常。但是,我注意到当从另一个屏幕(或 showModalBottomSheet
之类的弹出窗口)调用 notifyListeners
时,我的 UI 不会收到通知。
我在 provider
中使用的方法看起来像这样,并将一个项目添加到 ListView:
void addEntry(http.Response response) {
Group group = Group.fromJson(jsonDecode(response.body));
groups.add(group);
notifyListeners();
}
至于 UI 整个屏幕被包裹在 Consumer
中。从屏幕中的按钮调用此方法工作正常并且列表已更新。从使用 showModalBottomSheet
创建的弹出窗口调用此方法不会更新 UI.
如何确保 UI 收到更改通知?
更新 #1:
我有一个像这样调用 showModalBottomSheet
的按钮:
showModalBottomSheet<void>(
...
context: context,
builder: (context) {
return Padding(
padding: MediaQuery.of(context).viewInsets,
child: AddWidget(model: Provider.of<GroupsProvider>(context)),
);
},
);
所以它创建了一个带有单独小部件的弹出窗口。当按下另一个按钮时,该单独的小部件依次执行此操作:
widget.model.createGroup(name, icon);
这个方法最终会调用addEntry
。正如我所说,这在没有弹出窗口的情况下工作得很好,但在弹出窗口中根本不起作用:/
Pop-ups 之类的 bottomsheets 很可能是从根导航器打开的,因此提供了不同的上下文,如果您的提供者不是在根导航器之上创建的,即在 MaterialApp 之上,则会导致此问题。
来自 showModalBottomSheet
的 builder
的 context
不是创建提供者的地方。
我能想到两种解决方案:
- 就在调用
showModalBottomSheet
之前,您可以创建对 Provider 的引用,然后将其传递给 AddWidget。
var provider = Provider.of<GroupsProvider>(context, listen:false);
showModalBottomSheet<void>(
...
context: context,
builder: (context) {
return Padding(
padding: MediaQuery.of(context).viewInsets,
child: AddWidget(model: provider),
);
},
);
- 使用
ChangeNotifierProvider.value
并将小部件包装在构建器中。
showModalBottomSheet<void>(
...
context: context,
builder: (_) {
return ChangeNotifierProvider.value(
value: Provider.of<GroupsProvider>(context, listen:false),
builder: (context, _) =>
Padding(
padding: MediaQuery.of(context).viewInsets,
child: AddWidget(model: Provider.of<GroupsProvider>(context)),
);
);
},
);
(2) 确保它下面的小部件树可以访问同一个 Provider 实例。对于新屏幕,您可以这样做:
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => ChangeNotifierProvider.value(...),
),
);
在调试模式下查看小部件检查器将帮助您更好地理解
我正在使用提供程序库进行状态管理,到目前为止一切正常。但是,我注意到当从另一个屏幕(或 showModalBottomSheet
之类的弹出窗口)调用 notifyListeners
时,我的 UI 不会收到通知。
我在 provider
中使用的方法看起来像这样,并将一个项目添加到 ListView:
void addEntry(http.Response response) {
Group group = Group.fromJson(jsonDecode(response.body));
groups.add(group);
notifyListeners();
}
至于 UI 整个屏幕被包裹在 Consumer
中。从屏幕中的按钮调用此方法工作正常并且列表已更新。从使用 showModalBottomSheet
创建的弹出窗口调用此方法不会更新 UI.
如何确保 UI 收到更改通知?
更新 #1:
我有一个像这样调用 showModalBottomSheet
的按钮:
showModalBottomSheet<void>(
...
context: context,
builder: (context) {
return Padding(
padding: MediaQuery.of(context).viewInsets,
child: AddWidget(model: Provider.of<GroupsProvider>(context)),
);
},
);
所以它创建了一个带有单独小部件的弹出窗口。当按下另一个按钮时,该单独的小部件依次执行此操作:
widget.model.createGroup(name, icon);
这个方法最终会调用addEntry
。正如我所说,这在没有弹出窗口的情况下工作得很好,但在弹出窗口中根本不起作用:/
Pop-ups 之类的 bottomsheets 很可能是从根导航器打开的,因此提供了不同的上下文,如果您的提供者不是在根导航器之上创建的,即在 MaterialApp 之上,则会导致此问题。
来自 showModalBottomSheet
的 builder
的 context
不是创建提供者的地方。
我能想到两种解决方案:
- 就在调用
showModalBottomSheet
之前,您可以创建对 Provider 的引用,然后将其传递给 AddWidget。
var provider = Provider.of<GroupsProvider>(context, listen:false);
showModalBottomSheet<void>(
...
context: context,
builder: (context) {
return Padding(
padding: MediaQuery.of(context).viewInsets,
child: AddWidget(model: provider),
);
},
);
- 使用
ChangeNotifierProvider.value
并将小部件包装在构建器中。
showModalBottomSheet<void>(
...
context: context,
builder: (_) {
return ChangeNotifierProvider.value(
value: Provider.of<GroupsProvider>(context, listen:false),
builder: (context, _) =>
Padding(
padding: MediaQuery.of(context).viewInsets,
child: AddWidget(model: Provider.of<GroupsProvider>(context)),
);
);
},
);
(2) 确保它下面的小部件树可以访问同一个 Provider 实例。对于新屏幕,您可以这样做:
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => ChangeNotifierProvider.value(...),
),
);
在调试模式下查看小部件检查器将帮助您更好地理解