tlserver / flutter_map_location_marker

A flutter map plugin for displaying device current location.
https://pub.dev/packages/flutter_map_location_marker
BSD 3-Clause "New" or "Revised" License
97 stars 81 forks source link

[Bug] Current position initialize with first positionStream update, which delays widget appear #49

Closed Pepslee closed 1 year ago

Pepslee commented 1 year ago

Layer doesn't build until the positionStream receives the first update. So if I`m not moving and have an accurate position, the layer doesn't build for a long time, because there are no events in positionStream.

  @override
  Widget build(BuildContext context) {
    if (_currentPosition != null) {
      return AnimatedLocationMarkerLayer(
        position: _currentPosition!,
        heading: _currentHeading,
        style: widget.style,
        moveAnimationDuration: widget.moveAnimationDuration,
        moveAnimationCurve: widget.moveAnimationCurve,
        rotateAnimationDuration: widget.rotateAnimationDuration,
        rotateAnimationCurve: widget.rotateAnimationCurve,
      );
    } else {
      return const SizedBox.shrink();
    }
  }

_currentPosition initialized by null by default.

So my proposition is to use Future builder with Geolocator.getCurrentPosition as future


@override
  Widget build(BuildContext context) {
    FutureBuilder(
      future: Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.high),
      builder: (BuildContext context, AsyncSnapshot snapshot) {
        if (snapshot.data != null) {
          Position position = snapshot.data;
          _currentPosition = LocationMarkerPosition(
            latitude: position.latitude,
            longitude: position.longitude,
            accuracy: position.accuracy,
          );
          return AnimatedLocationMarkerLayer(
            position: _currentPosition!,
            heading: _currentHeading,
            style: widget.style,
            moveAnimationDuration: widget.moveAnimationDuration,
            moveAnimationCurve: widget.moveAnimationCurve,
            rotateAnimationDuration: widget.rotateAnimationDuration,
            rotateAnimationCurve: widget.rotateAnimationCurve,
          );
        } else {
          return const SizedBox.shrink();
        }
      },
    );

  }
tlserver commented 1 year ago

According to the document, calling getPositionStream() will starts all location sensors so it should have first update very soon. Are you using the default value of positionStream or providing your own positionStream? Are you already using location sensors before initializing the map?

I created a patch but no time to test it. It may help if you are using default value of positionStream.

Index: lib/src/data_stream_factory.dart
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/lib/src/data_stream_factory.dart b/lib/src/data_stream_factory.dart
--- a/lib/src/data_stream_factory.dart  (revision 1735ec9f60b8b22d9bf88ca0861984b8f8ee3f3d)
+++ b/lib/src/data_stream_factory.dart  (date 1669189744545)
@@ -18,7 +18,19 @@
   Stream<LocationMarkerPosition> geolocatorPositionStream({
     Stream<Position>? stream,
   }) {
-    return (stream ?? Geolocator.getPositionStream()).map((Position position) {
+    Stream<Position>? positionStream = stream;
+    if (positionStream == null) {
+      final streamController = StreamController<Position>();
+      Geolocator.getLastKnownPosition()
+          .then((lastKnown) {
+            if (lastKnown != null) {
+              streamController.sink.add(lastKnown);
+            }
+            streamController.sink.addStream(Geolocator.getPositionStream());
+          });
+      positionStream = streamController.stream;
+    }
+    return positionStream.map((Position position) {
       return LocationMarkerPosition(
         latitude: position.latitude,
         longitude: position.longitude,
Pepslee commented 1 year ago

Yes, I'm using the default value of positionStream. Yes, I'm already using location sensors before initializing the map. I think would be better to use Geolocator.getCurrentPosition() instead of Geolocator.getLastKnownPosition() in the patch you suggested. Geolocator.getLastKnownPosition() does not always work correctly, from my experience.

One more thin, this pull request seems to solve the problem.

tlserver commented 1 year ago

Is seem that there is a bug still does not fixed. So I think getLastKnownPosition() maybe better. See also https://github.com/Baseflow/flutter-geolocator/issues/999.

Based on the name of that method getLastKnownPosition(), 1) if location sensors are initialized before, it should return the position; 2) otherwise, location sensors are not initialized before, it should return null, but calling getPositionStream() will start location sensors and fire an location update very soon.

But it is not tested.

Pepslee commented 1 year ago

@tlserver Hi, there one more little problem. When I run app at the first time, map with location marker build at first, and then I ask user for location permissions, after approving location marker doesn't appear at all, until the app restart (location widget rebuild).

tlserver commented 1 year ago

@tlserver Hi, there one more little problem. When I run app at the first time, map with location marker build at first, and then I ask user for location permissions, after approving location marker doesn't appear at all, until the app restart (location widget rebuild).

In which OS, you found this issue?

Pepslee commented 1 year ago

@tlserver android 10, one plus 5.

speeteco commented 1 year ago

@tlserver Hi, there one more little problem. When I run app at the first time, map with location marker build at first, and then I ask user for location permissions, after approving location marker doesn't appear at all, until the app restart (location widget rebuild). @tlserver

Hi, i have the same problem