Home > Mobile >  ProxyProvider - Struggling using it to return List<int>
ProxyProvider - Struggling using it to return List<int>

Time:08-16

i'm new to flutter and i'm trying to use ProxyProvider to return List depending on List here's the code in main.dart

providers: [
        FutureProvider<List<Mixer>>(
            create: (_) => mixerdbService.retrieveMixers(),
            initialData: <Mixer>[]),
        ProxyProvider<List<Mixer>, List<int>>(update: (_, mixers, __) {
          final List<int> ints = [];

          for (var mixer in mixers) {
            shipmentdbService
                .retrieveNumberOfShipmentsByMixerId(mixer.id)
                .then((value) => ints.add(value));
          }
          return ints;
        }),

and this the method retrieveNumberOfShipmentsByMixerId

  Future<int> retrieveNumberOfShipmentsByMixerId(String? mixerId) async {
    QuerySnapshot<Map<String, dynamic>> snapshot = await _db
        .collection("shipments")
        .where("mixer_id", isEqualTo: mixerId)
        .get();
    return snapshot.docs.length;
  }

The provider value is an empty list. i think that there is a mistake in the logic in update method of the proxyprovider. if the question is not clear, please ask me for more details

Solution

step#1

        FutureProvider<List<Mixer>>(
            create: (_) => mixerdbService.retrieveMixers(),
            initialData: <Mixer>[]),
        ProxyProvider<List<Mixer>, Future<List<int>>>(
            update: (_, mixers, __) async {
          final List<int> ints = [];

          for (var mixer in mixers) {
            final value = await shipmentdbService
                .retrieveNumberOfShipmentsByMixerId(mixer.id);
            ints.add(value);
          }
          return ints;
        }),

step#2: Resolve the Future from the Provider by using FutureBuilder

FutureBuilder<List<int>>(
        future: context.read<Future<List<int>>>(),
        builder: (_, snapshot) {
          if (snapshot.hasData &&
              snapshot.data!.isNotEmpty &&
              listOfMixers.isNotEmpty) {
            return ListView.builder(
                itemCount: listOfMixers.length,
                itemBuilder: (_, index) {
                  return MixerCard(
                      mixer: listOfMixers[index],
                      numberOfShipments: snapshot.data![index]);
                });
          }
          return Center(
            child: CircularProgressIndicator(),
          );
        },
      ),

This solution is okay, but i'm still searching for another solution without the use of FutureBuilder.

CodePudding user response:

The problem is that the ProxyProvider is returning a list that's not populated yet because of the async calls with .then.

To solve it return a Future<List<int>> instead and make the update function async. It's going to be like below:

ProxyProvider<List<Mixer>, Future<List<int>>>(
    update: (_, mixers, __) async {
  final List<int> ints = [];

  for (var mixer in mixers) {
    final value = await shipmentdbService
        .retrieveNumberOfShipmentsByMixerId(mixer.id);
    ints.add(value);
  }
  return ints;
}),

Solution 1

Then add another FutureProvider like so:

FutureProvider<List<int>>(
  create: (context) => context.read<Future<List<int>>>(),
  initialData: [],
),

This way it's easy to use it like:

final listOfMixers = context.watch<List<Mixer>>();
final listOfInts = context.watch<List<int>>();
return Scaffold(
  body: listOfMixers.isNotEmpty && listOfInts.isNotEmpty   // <- Here
      ? ListView.builder(
          itemCount: listOfMixers.length,
          itemBuilder: (context, index) {
            return MixerCard(
              mixer: listOfMixers[index],
              numberOfShipments: listOfInts[index],
            );
          })
      : const Center(
          child: CircularProgressIndicator(),
        ),
);

Solution 2

Or use a FutureBuilder to get the List<int> out of the Future. Something like the following:

FutureBuilder<List<int>>(
  future: context.read<Future<List<int>>>(),
  builder: (context, snapshot) {
    if (snapshot.hasError) {
      return ErrorPage();
    }

    if (snapshot.data == null) {
      return Center(child: CircularProgressIndicator());
    }

    final listLengths = snapshot.data;
    // Do something with `listLengths`
  }),
  • Related