如何在Flutter Provider中正确初始化Future

时间:2020-02-28 04:19:55

标签: flutter dart flutter-provider

所以我正试图通过“未来通话”在我的提供商中建立一个列表。

到目前为止,我在下面有以下ChangeNotifier类:

class MainProvider extends ChangeNotifier {
  List<dynamic> _list = <dynamic>[];
  List<dynamic> get list => _list;
  int count = 0;

  MainProvider() {
    initList();
  }

  initList() async {
    var db = new DatabaseHelper();

    addToList(Consumer<MainProvider>(
        builder: (_, provider, __) => Text(provider.count.toString())));

    await db.readFromDatabase(1).then((result) {
      result.forEach((item) {
        ModeItem _modelItem= ModeItem.map(item);

        addToList(_modelItem);
      });
    });
  }

  addToList(Object object) {
    _list.add(object);
    notifyListeners();
  }

  addCount() {
    count += 1;
    notifyListeners();
  }
}

但是,只要我使用 list 值,就会发生这种情况:

  1. 我可以确认我的initList函数正确执行
  2. 列表值中的初始内容是 我首先通过 addToList 函数插入的 Text()小部件,这意味着列表上目前只有一项
  3. 执行热重装时,列表的其余内容似乎现在出现了

注意:

  1. 我在AnimatedList小部件中使用 list 的值,所以我 应该显示列表
  2. 的内容
  3. 最初显示的是我的列表值的内容只是一项
  4. 我的列表值似乎在更新过程中不会自动更新 执行我的未来通话
  5. 但是,当我尝试调用addCount函数时,通常 无需执行热重装即可更新 count 的值- 这个似乎运作正常
  6. “未来”通话似乎未正确更新 我的列表值的内容

我真正关心的是,在初始加载时,我的列表值没有 按预期正确初始化所有值

希望你们可以在这一方面帮助我。谢谢。

更新:下面显示了我如何使用上面的ChangeNotifierClass

class ParentProvider extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider<MainProvider>(
          create: (context) => MainProvider(),
        ),
      ],
      child: ParentWidget(),
    );
  }
}

class ParentWidget extends StatelessWidget {
  final GlobalKey<AnimatedListState> listKey = GlobalKey<AnimatedListState>();

  @override
  Widget build(BuildContext context) {
    var mainProvider = Provider.of<MainProvider>(context);

    buildItem(BuildContext context, int index, Animation animation) {
      print('buildItem');

      var _object = mainProvider.list[index];
      var _widget;

      if (_object is Widget) {
        _widget = _object;
      } else if (_object is ModelItem) {
        _widget = Text(_object.unitNumber.toString());
      }

      return SizeTransition(
        key: ValueKey<int>(index),
        axis: Axis.vertical,
        sizeFactor: animation,
        child: InkWell(
          onTap: () {
            listKey.currentState.removeItem(index,
                (context, animation) => buildItem(context, index, animation),
                duration: const Duration(milliseconds: 300));
            mainProvider.list.removeAt(index);
            mainProvider.addCount();
          },
          child: Card(
            child: Padding(
              padding: const EdgeInsets.all(32.0),
              child: _widget,
            ),
          ),
        ),
      );
    }

    return Scaffold(
      appBar: AppBar(),
      body: Container(
        color: Colors.white,
        child: Padding(
          padding: const EdgeInsets.all(32.0),
          child: mainProvider.list == null
              ? Container()
              : AnimatedList(
                  key: listKey,
                  initialItemCount: mainProvider.list.length,
                  itemBuilder:
                      (BuildContext context, int index, Animation animation) =>
                          buildItem(context, index, animation),
                ),
        ),
      ),
    );
  }
}

1 个答案:

答案 0 :(得分:2)

您正在从StatelessWidget检索提供者。因此,ChangeNotifier无法触发窗口小部件进行重建,因为没有状态可以重建。您必须将ParentWidget转换为StatefulWidget,或者需要使用Consumer而不是Provider.of来获得提供者:

class ParentWidget extends StatelessWidget {
  final GlobalKey<AnimatedListState> listKey = GlobalKey<AnimatedListState>();

  @override
  Widget build(BuildContext context) {
    return Consumer<MainProvider>(
      builder: (BuildContext context, MainProvider mainProvider, _) {
        ...
      }
    );
  }

顺便说一句,您使用提供程序的方法是将MainProvider添加到其提供程序,然后从其直接子级中检索它。如果这是您唯一要检索MainProvider的地方,这将使提供程序模式变得多余,因为您可以轻松地在ParentWidget中声明它,甚至可以使用{{1}获取图像列表}。使用提供程序是朝着适当的状态管理迈出的重要一步,但也要避免过度设计您的应用程序。