flutter - 使用提供者获取数据 onLoad
问题描述
我来自 Android 开发,对 Flutter 开发非常陌生,我遇到了用于状态管理的 ScopedModel 和 Provider,并为我的用例选择了 Provider。我的用例是登录后,仪表板应该用数据呈现。我创建了一个扩展 ChangeNotifier 的 ViewModel,并希望使用它以便我可以在不同的小部件中重用这些数据。我不完全确定如何使用我的 ViewModel 加载小部件的数据。一些人可以帮助我正确的设计模式。
abstract class ViewModel extends ChangeNotifier {
}
class EventViewModel extends ViewModel {
EventDataState _eventDataState = EventDataUnInitialized();
EventDataState get eventDataState => _eventDataState;
set eventDataState(EventDataState value) {
_eventDataState = value;
notifyListeners();
}
gatherEvents() {
eventDataState = EventDataLoading();
EventService.create().getEvents().then((data){
var responseData = json.decode(data.bodyString);
eventDataState = EventDataLoaded(
responseData.map((each) => new EventData.fromJson(each)).toList());
}).catchError((err){
eventDataState = EventDataLoadFailed("Failed to do something");
});
}
}
class DashboardPage extends StatefulWidget {
static const routename = "/dashboard";
@override
_DashboardPageState createState() => _DashboardPageState();
}
class _DashboardPageState extends State<DashboardPage> {
@override
Widget build(BuildContext context) {
return Consumer<EventViewModel>(
builder: (context, vm, child) {
if (vm.eventDataState is EventDataUnInitialized) {
vm.gatherEvents();
return Scaffold(body: Container(),);
}else if (vm.eventDataState is EventDataLoading) {
return Scaffold(body: Container(child: Center(child: CircularProgressIndicator(),),),);
}else if (vm.eventDataState is EventDataLoadFailed) {
return Scaffold(body: Container(child: Center(child: Text("Error Loading Data."),),),);
}else{
return Scaffold(body: Container(child: Center(child: Text("Data done loading..."),),),);
}
},
);
}
}
我得到的错误是:
I/flutter (30492): ══╡ EXCEPTION CAUGHT BY FOUNDATION LIBRARY ╞════════════════════════════════════════════════════════
I/flutter (30492): The following assertion was thrown while dispatching notifications for EventViewModel:
I/flutter (30492): setState() or markNeedsBuild() called during build.
I/flutter (30492): This ListenableProvider<EventViewModel> widget cannot be marked as needing to build because the
I/flutter (30492): framework is already in the process of building widgets. A widget can be marked as needing to be
I/flutter (30492): built during the build phase only if one of its ancestors is currently building. This exception is
I/flutter (30492): allowed because the framework builds parent widgets before children, which means a dirty descendant
I/flutter (30492): will always be built. Otherwise, the framework might not visit this widget during this build phase.
I/flutter (30492): The widget on which setState() or markNeedsBuild() was called was:
I/flutter (30492): ListenableProvider<EventViewModel>
I/flutter (30492): The widget which was currently being built when the offending call was made was:
I/flutter (30492): Consumer<EventViewModel>
解决方案
您可以使用 SchedulerBinding 来防止此异常:
备选方案 1:
initState() {
super.initState();
final gatherEvents =
Provider.of<EventViewModel>(context, listen: false).gatherEvents;
SchedulerBinding.instance.addPostFrameCallback((_) => gatherEvents());
}
备选方案 2:
initState() {
super.initState();
Future.microtask(() =>
Provider.of<EventViewModel>(context, listen: false).gatherEvents();
);
}
推荐阅读
- python - 在 Python 中迭代和更新 JSON 文件
- deep-learning - 关于 NN 中的 Dropout
- youtube-data-api - YouTube Live Streaming API 中的最大 ID 长度是多少
- c++ - 如何仅继承类的方法,而不是整个类本身(C++)
- javascript - 如何识别 Linking.addEventListener 中的数据?
- microsoft-graph-api - 直接路由报告 - Microsoft Teams
- azure-data-factory-2 - 如何为 CI/CD 托管的 ADF 实例共享 Azure Datafactory 自托管集成运行时
- java - 通过Kafka失效的多个应用程序实例的Spring本地缓存
- php - Laravel 图像规则验证不适用于 Laravel 8,但适用于 Laravel 7 | 拉拉维尔 | 图片 | 验证
- jquery - 如何禁用按钮,直到填写所有必填字段