Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Streambuilder not receiving some snapshot data

Tags:

flutter

dart

I am just testing some streams from a GPS. I could plug in the gps stream directly, but I want to separate this for the moment. So I can using a StreamBuilder with my own created stream.

This all seems to be working, but the Streambuilder seems to 'miss' certain snapshots, which has me confused. Shouldn't it be guaranteed to receive all data from the stream (if it's not a broadcast)? Or am I using streams incorrectly ?

If you look at the data added/received, I can see count 5 & 7 were both added, but never received. If I just 'listen' the data without the StreamBuilder, all of the data seems to appear.

Streambuilder code:

Widget build(BuildContext context) {

    final ApplicationBloc bloc = BlocProvider.of<ApplicationBloc>(context);

    return StreamBuilder<Map<String, dynamic>>(
        stream: bloc.gps.stream,
        builder: (BuildContext context, AsyncSnapshot<Map<String, dynamic>> snapshot){
          if( snapshot.hasData ) {
            print("Receiving ${snapshot.data['count']}");
            return Text("${snapshot.data['timestamp']}\n${snapshot.data['latitude']},${snapshot.data['longitude']}\n",
              style: Theme.of(context).textTheme.display1,);
          } else {
            return Text('waiting for GPS...', style: Theme.of(context).textTheme.display1,);
          }
        }
    );

  }

Add to stream code:

var locationOptions = LocationOptions(accuracy: LocationAccuracy.bestForNavigation, distanceFilter: 0, timeInterval: 1, forceAndroidLocationManager: false);

    final Geolocator geoLocator = new Geolocator();
    geoLocator.getPositionStream( locationOptions ).listen(
            (Position position) {
              _count++;
              Map<String, dynamic> listenerCurrentLocation = {
                'latitude'  : position.latitude,
                'longitude' : position.longitude,
                'speed'     : position.speed,
                'accuracy'  : position.accuracy,
                'altitude'  : position.altitude,
                'timestamp' : position.timestamp,
                'count'     : _count,
              };
              print( "Adding: $listenerCurrentLocation");
              gpsController.sink.add( listenerCurrentLocation );
            });

Output from Run console

I/flutter (16345): Receiving 2
I/flutter (16345): Adding: {latitude: 50.829798333333336, longitude: -0.18484833333333334, speed: 0.0, accuracy: 20.0, altitude: 11.7, timestamp: 2019-01-13 14:21:02.000Z, count: 3}
I/flutter (16345): Receiving 3
I/flutter (16345): Adding: {latitude: 50.829798333333336, longitude: -0.18484833333333334, speed: 0.0, accuracy: 20.0, altitude: 11.7, timestamp: 2019-01-13 14:21:03.000Z, count: 4}
I/flutter (16345): Receiving 4
I/flutter (16345): Adding: {latitude: 50.829798333333336, longitude: -0.18484833333333334, speed: 0.0, accuracy: 20.0, altitude: 11.7, timestamp: 2019-01-13 14:21:04.000Z, count: 5}
I/flutter (16345): Adding: {latitude: 50.829798333333336, longitude: -0.18484833333333334, speed: 0.0, accuracy: 20.0, altitude: 0.0, timestamp: 2019-01-13 14:21:04.000Z, count: 6}
I/flutter (16345): Receiving 6
I/flutter (16345): Adding: {latitude: 50.829798333333336, longitude: -0.18484833333333334, speed: 0.0, accuracy: 20.0, altitude: 11.7, timestamp: 2019-01-13 14:21:05.000Z, count: 7}
I/flutter (16345): Adding: {latitude: 50.829798333333336, longitude: -0.18484833333333334, speed: 0.0, accuracy: 20.0, altitude: 0.0, timestamp: 2019-01-13 14:21:05.000Z, count: 8}
I/flutter (16345): Receiving 8
like image 348
Ian Avatar asked Jan 13 '19 14:01

Ian


Video Answer


1 Answers

This is the expected behavior.

As opposed to using stream.listen, StreamBuilder calls its builder only when a new frame is requested.

It is fine because StreamBuilder should be used only to build the layout, in which case it doesn't matter if a value is missed.

If this behavior is undesired, consider switching to a manual listening instead:

Stream stream;
StreamSubscription sub;

initState() {
  super.initState();
  sub = stream.listen((value) {
    // do something with `value`
  });
}


dispose() {
  sub.cancel();
  super.dispose();
}
like image 195
Rémi Rousselet Avatar answered Oct 21 '22 15:10

Rémi Rousselet