1

I have a StreamController which should update a List but it doesn't happen:

class LocationService {
    StreamController<List<bg.Geofence>> geofencesController = StreamController<List<bg.Geofence>>();

    updateGeofences(geofences) {
        logger.i('listing geofences $geofences');
        geofencesController.add(List.from(list));
    }
}

When I call updateGeofences I got many geofences in logs. But widget are not rebuilt!

Here is my providers setup:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
        providers: [
          StreamProvider<List<bg.Geofence>>.value(
              updateShouldNotify: (_, __) {
                logger.i('updateShouldNotify, $_, $__');
                return true;
              },
              initialData: List<bg.Geofence>(),
              stream: LocationService().geofencesController.stream)
        ],
        child: MaterialApp()
     );
  }
}

When I listen directly from my service with

geofencesController.stream.listen((onData) {
  logger.i('Got eem! $onData');
});

The streams emits new data... But not in the StreamProvider: updateShouldNotify is never called (I tried without luck this answer's solutions)

Here is how I get my data in view:

class GPSView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    List<bg.Geofence> geofences = Provider.of<List<bg.Geofence>>(context);

But this list remains empty.

I have another StreamController with a simple Map which works perfectly. What's wrong?

Hugo H
  • 6,029
  • 5
  • 37
  • 57
  • 1
    That may not be the problem, but you shouldn't use `.value` constructor here. See [this](https://pub.dev/documentation/provider/latest/provider/ChangeNotifierProvider-class.html) The `Creating a ChangeNotifier` part applies to StreamProvider too – Rémi Rousselet Sep 04 '19 at 12:42
  • 1
    `LocationService().geofencesController.stream` creates a new `LocationService` and new `geofencesController` so you are using two different controllers – pskink Sep 04 '19 at 12:43
  • Hi @RémiRousselet! I followed https://medium.com/flutter-community/build-a-location-service-in-flutter-367a1b212f7a tutorial, which is using GetIt() to keep LocationService as a singleton. Isn't it? `locator.registerLazySingleton(() => LocationService());` – Hugo H Sep 04 '19 at 12:48
  • So, you got me on the track! It has nothing to do with the StreamProvider. I just need to call `locator()` instead of `LocationService()`. Cheers! – Hugo H Sep 04 '19 at 13:04
  • Using provider with get_it is not a good idea. They are concurrents. – Rémi Rousselet Sep 04 '19 at 13:26
  • Hmm. What are my options? ProxyProviders? Should I follow this? https://medium.com/flutter-community/flutter-provider-v3-architecture-using-proxyprovider-for-injection-62cf5c58ea52 Thanks for your feedbacks! – Hugo H Sep 04 '19 at 13:47
  • Make a Provider for the `LocationService` instead of a locator. Then use a Consumer that builds a StreamProvider.value from the service. – Rémi Rousselet Sep 04 '19 at 14:18

1 Answers1

1

So thanks to @pskink & @RémiRoussele comments I managed to fix my issue:

I was recreating a LocationService by calling LocationService().geofencesController.stream.

I updated my code to

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
        providers: [
          StreamProvider<List<bg.Geofence>>(
            builder: (_) => locator<LocationService>().geofencesController,
            initialData: List<bg.Geofence>(),
          ),
        ],
        child: MaterialApp();
  }
}

And everything works now! Cheers!

Hugo H
  • 6,029
  • 5
  • 37
  • 57