简体   繁体   中英

Using geolocator GPS stream with Riverpod StreamProvider

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.

This line you terminate the socket immediately:

ref.onDispose(socket?.cancel());

Try it instead:

ref.onDispose(() => socket?.cancel());

Create a provider to hold position value

final locationProvider = StateProvider<Position>((ref){
  return Position(longitude: 0.0, latitude: 0.0, timestamp: DateTime.now(), accuracy: 0, altitude: 0, heading: 0, speed: 0,      speedAccuracy: 0);
});

Update the value of locationProvider inside Geolocator.getPositionStream stream

final locationStateProvider = StreamProvider.autoDispose<Position>((ref){
  LocationSettings locationSettings = const LocationSettings(accuracy: LocationAccuracy.medium, distanceFilter: 20);
  return Geolocator.getPositionStream(locationSettings: locationSettings).map((position){
    ref.read(locationProvider.notifier).state = position;
    return position;
  });
});

Watch (initialize) for locationStateProvider anywhere in parent tree. No need to assign it to anything

ref.watch(locationStateProvider);

Watch for location provider

final location = ref.watch(locationProvider);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM