在flutter中从initState调用scopedModel

时间:2018-08-16 18:59:55

标签: android dart flutter

我有一个scopedModel类,可在其中提取数据。问题是,我无法使用拥有所有api请求的作用域模型从InitState方法呈现此数据。该方法正在被调用,但内部调用未被调用,因此页面的初始状态无法正确显示。

void initState() {
    print("Check initState");
    super.initState();
    ScopedModelDescendant<MainModel>(
        builder: (BuildContext context, Widget child, MainModel model) {
      print("Get into the scoped model");
      model.fecthCars();
      model.fecthCities();
      model.fecthBuys(model.getUserDto.token);
      print(model.getBuys().length);
      return;
    });
  }

不会调用任何fetches(Api请求)。然后scopedModel返回一个小部件。我需要在第一次进入经理时进行更新,仅此而已。无需再次调用。这可能吗?还是应该在我需要的每个文件中对我的api请求进行硬编码?

更新

如果已经设置了作用域模型类,则可以在其内部设置这样的Future

mixin MyModel on Model {
    Future<TypeToReturn> methodName(String param) async {
    Uri uri = new Uri.http('serverUrl', 'api/call');

    return await http.get(uri).then((http.Response response) {
      final List<dynamic> myResponse= json.decode(response.body);

      return myResponse;
    }).catchError((error) {
      print(error);
    });
  }
}

后期,您可以设置FutureBuilder

Widget _buildBody(BuildContext context, MainModel model) {

    return FutureBuilder(
      future:  model.methodName(someString), //This is the method name above
      builder: (context, AsyncSnapshot<TypeToReturn> snapshot) { //type u return
        if (!snapshot.hasData) {
          return Center(
            child: CircularProgressIndicator(),
          );
        } else {
          if (snapshot.data.length == 0)
            return Center(
              child: Text(
                "No Data Found",
                textAlign: TextAlign.center,
                style: TextStyle(
                  fontSize: 16.0,
                ),
              ),
            );

          return (create your own widget with the data inside the snapshot)
        }
      },
    );
  }

希望这会使我做得更多。

3 个答案:

答案 0 :(得分:3)

我偶然发现以下解决方案:

在StatefulWidget的State类中,我这样做:

@override
void initState() {
  super.initState();
  // and here...
  MyModel model = ScopedModel.of(context);
  // now I can do with the model whatever I need to do:
  Text someVar = model.initialText;
  model.getValuesFromSomewhere();
  // and so on
}

我认为,这是解决原始问题所指出的最简单方法。

答案 1 :(得分:2)

我认为您对ScopedModel和ScopedModelDescendant的观点有些误解。这些工作原理的基本思想是,使用有效模型创建ScopedModel,然后将其用于应用程序的其他部分。

但是,应该在其中一个小部件的build()函数中使用ScopedModelDescendant,并且还应将其作为小部件树的一部分。之所以没有调用您的提取方法,是因为它不在小部件树中,因此永远不会调用构建函数。

我建议改为将fetch方法从模型中移出,并移入其他某个类(可能称为通信器或控制器之类)。接下来,我将进行建模,以便从该控制器进行异步调用的结果实例化该模型。

最后,我不建议实例化一个无效的模型然后在获取数据后就更改模型,我建议使用FutureBuilder-这样,您就可以根据将来是否可以控制构建什么进行中,成功或失败。

所以看起来像这样(伪代码)。

StatefulWidget (MyApp or whatever you call it)
  build =>
     FutureBuilder(<fetch model data>, ...)
       (if done)
          ScopedModel<MainModel>
             .... (whatever your code has here)
               ScopedModelDescendant<MainModel>
                  (build using the model)             
       (if not done)
          Loading.... (if needed)

如果您绝对希望模型始终存在,我仍然建议您在顶部的有状态小部件中进行访存,并简单地更改在其下面传递的模型,而不是在加载数据后修改现有模型。

答案 2 :(得分:1)

这是我的解决方案,希望对您有帮助

@override
  void initState() {
    super.initState();
    User user = ScopedModel.of(this.context);
    _controllerFirstName.text = user.userData['first_name'];
    _controllerLastName.text = user.userData['last_name'];
    }