简体   繁体   中英

How to properly initialize a Future in Flutter Provider

so I am trying to build up a list in my provider from a Future Call.

So far, I have the following ChangeNotifier class below:

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();
  }
}

However, this is what happens whenever I use the list value:

  1. I can confirm that my initList function is executing properly
  2. The initial content from the list value that is available is the Text() widget that I firstly inserted through the addToList function, meaning it appears that there is only one item in the list at this point
  3. When I perform Hot Reload, the rest of the contents of the list seems to appear now

Notes:

  1. I use the value of list in a AnimatedList widget, so I am supposed to show the contents of list
  2. What appears initially is that the content of my list value is only one item
  3. My list value doesn't seem to automatically update during the execution of my Future call
  4. However, when I try to call the addCount function, it normally updates the value of count without needing to perform Hot Reload - this one seems to function properly
  5. It appears that the Future call is not properly updating the contents of my list value

My actual concern is that on initial loading, my list value doesn't properly initialize all it's values as intended

Hoping you guys can help me on this one. Thank you.

UPDATE: Below shows how I use the ChangeNotifierClass above

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),
                ),
        ),
      ),
    );
  }
}

You are retrieving your provider from a StatelessWidget . As such, the ChangeNotifier can't trigger your widget to rebuild because there is no state to rebuild. You have to either convert ParentWidget to be a StatefulWidget or you need to get your provider using Consumer instead of 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, _) {
        ...
      }
    );
  }

As an aside, the way you are using provider is to add the MainProvider to its provider and then retrieve it from within its immediate child. If this is the only place you are retrieving the MainProvider , this makes the provider pattern redundant as you can easily just declare it within ParentWidget , or even just get your list of images using a FutureBuilder . Using provider is a good step toward proper state management, but also be careful of over-engineering your app.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM