首页 > 解决方案 > 使用提供者获取数据 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>

标签: flutter

解决方案


您可以使用 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();
  );
}

推荐阅读