I’m wrestling with using the streaming GPS feature (StreamSubscription) of the geolocator package with the StreamProvider function of Riverpod in order have a global variable that has constantly updated user GPS coordinates. Using the geolocator package I am able to get and console log the user’s live GPS coords, but I’m not able to get those streaming values into a Riverpod variable. My code is below. Would appreciate any thoughts or tips. Many thanks.
https://riverpod.dev/docs/providers/stream_provider
https://pub.dev/documentation/geolocator/latest/
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:geolocator/geolocator.dart';
import 'dart:developer' as developer;
final userGpsProvider = StreamProvider<Position>((ref) {
LocationSettings locationSettings = const LocationSettings(
accuracy: LocationAccuracy.bestForNavigation,
distanceFilter: 20, // in meters before an update is generated
);
Position? gpsPosition;
final StreamSubscription<Position> socket =
Geolocator.getPositionStream(locationSettings: locationSettings)
.listen((Position? position) {
developer.log('position ${position.toString()}');
gpsPosition = position as Position;
});
ref.onDispose(socket?.cancel());
developer.log('gpsPosition ${gpsPosition.toString()}');
developer.log('socket ${socket.toString()}');
return gpsPosition as Stream<Position>;
});
I’ve modified the above code and taken this a step further and have a working version of a sorts. Unfortunately it involves creating some new globals, which I don’t want to do.
/// create global variables position, lng and lat
/// (I don't want to do this, but it works)
late Position position;
String? lng = '';
String? lat = '';
final userGpsProvider = StreamProvider<Position>((ref) async* {
LocationSettings locationSettings = const LocationSettings(
accuracy: LocationAccuracy.bestForNavigation,
distanceFilter: 20, // in meters before an update is generated
);
final StreamSubscription<Position> socket =
Geolocator.getPositionStream(locationSettings: locationSettings)
.listen((Position? position) {
developer.log('position ${position.toString()}');
lng = position?.longitude.toString();
lat = position?.latitude.toString();
});
ref.onDispose(() => socket.cancel());
});
and then, somewhere else, I call:
final dynamic userGPS = ref.watch(userGpsProvider);
developer.log('$userGPS.toString()'); // AsyncLoading<Position>()
developer.log('from main lng: $lng'); // -74.23
developer.log('from main lat: $lat'); // 54.23
The globals lng and lat do have correct values, but I only get AsyncLoading in userGPS. I’m hoping to have lat/lng values in userGPS via the Riverpod provider userGpsProvider, and to not have to use global lng and lat. I’m obviously not getting something right with Riverpod StreamProvider and would appreciate any help. Thanks.
2
Answers
This line you terminate the socket immediately:
Try it instead:
Create a provider to hold position value
Update the value of locationProvider inside Geolocator.getPositionStream stream
Watch (initialize) for
locationStateProvider
anywhere in parent tree. No need to assign it to anythingWatch for location provider