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
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();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With