在 onLoad 中使用提供者获取数据

mah*_*024 1 flutter

我来自 Android 开发,对 Flutter 开发非常陌生,我遇到过用于状态管理的 ScopedModel 和 Provider,并且我选择 Provider 作为我的用例。我的用例是登录后,仪表板应该用数据呈现。我创建了一个扩展 ChangeNotifier 的 ViewModel,并希望使用它,以便我可以在不同的小部件之间重用此数据。我不完全确定如何使用我的 ViewModel 来加载小部件的数据。有人可以帮助我制定正确的设计模式吗?

\n\n
abstract class ViewModel extends ChangeNotifier {\n}\n\nclass EventViewModel extends ViewModel {\n  EventDataState _eventDataState = EventDataUnInitialized();\n\n  EventDataState get eventDataState => _eventDataState;\n\n  set eventDataState(EventDataState value) {\n    _eventDataState = value;\n    notifyListeners();\n  }\n\n  gatherEvents() {\n    eventDataState = EventDataLoading();\n    EventService.create().getEvents().then((data){\n      var responseData = json.decode(data.bodyString);\n      eventDataState = EventDataLoaded(\n          responseData.map((each) => new EventData.fromJson(each)).toList());\n    }).catchError((err){\n      eventDataState = EventDataLoadFailed("Failed to do something");\n    });\n  }\n}\n\n\nclass DashboardPage extends StatefulWidget {\n  static const routename = "/dashboard";\n\n  @override\n  _DashboardPageState createState() => _DashboardPageState();\n}\n\n    class _DashboardPageState extends State<DashboardPage> {\n\n      @override\n      Widget build(BuildContext context) {\n        return Consumer<EventViewModel>(\n          builder: (context, vm, child) {\n            if (vm.eventDataState is EventDataUnInitialized) {\n              vm.gatherEvents();\n              return Scaffold(body: Container(),);\n            }else if (vm.eventDataState is EventDataLoading) {\n              return Scaffold(body: Container(child: Center(child: CircularProgressIndicator(),),),);\n            }else if (vm.eventDataState is EventDataLoadFailed) {\n              return Scaffold(body: Container(child: Center(child: Text("Error Loading Data."),),),);\n            }else{\n              return Scaffold(body: Container(child: Center(child: Text("Data done loading..."),),),);\n            }\n          },\n        );\n      }\n    }\n
Run Code Online (Sandbox Code Playgroud)\n\n

我得到的错误是:

\n\n
I/flutter (30492): \xe2\x95\x90\xe2\x95\x90\xe2\x95\xa1 EXCEPTION CAUGHT BY FOUNDATION LIBRARY \xe2\x95\x9e\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\nI/flutter (30492): The following assertion was thrown while dispatching notifications for EventViewModel:\nI/flutter (30492): setState() or markNeedsBuild() called during build.\nI/flutter (30492): This ListenableProvider<EventViewModel> widget cannot be marked as needing to build because the\nI/flutter (30492): framework is already in the process of building widgets.  A widget can be marked as needing to be\nI/flutter (30492): built during the build phase only if one of its ancestors is currently building. This exception is\nI/flutter (30492): allowed because the framework builds parent widgets before children, which means a dirty descendant\nI/flutter (30492): will always be built. Otherwise, the framework might not visit this widget during this build phase.\nI/flutter (30492): The widget on which setState() or markNeedsBuild() was called was:\nI/flutter (30492):   ListenableProvider<EventViewModel>\nI/flutter (30492): The widget which was currently being built when the offending call was made was:\nI/flutter (30492):   Consumer<EventViewModel>\n
Run Code Online (Sandbox Code Playgroud)\n

isa*_*ior 8

您可以使用 SchedulerBinding 来防止此异常:

替代方案 1:

initState() {
  super.initState();
  final gatherEvents =
      Provider.of<EventViewModel>(context, listen: false).gatherEvents;
  SchedulerBinding.instance.addPostFrameCallback((_) => gatherEvents());
}
Run Code Online (Sandbox Code Playgroud)

替代方案 2:

initState() {
  super.initState();
  Future.microtask(() =>
    Provider.of<EventViewModel>(context, listen: false).gatherEvents();
  );
}
Run Code Online (Sandbox Code Playgroud)