Flutter: How do I update markers' position in google map using Getx Obx?
Asked Answered
L

1

5

I have following view

import 'dart:async';
import 'package:get/get.dart';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import '../../Controllers/mapview_controller.dart';

class MapViewerPage extends StatelessWidget {
  MapViewerPage({Key? key}) : super(key: key);

  final MapViewController mapcontroller = MapViewController();
  final Completer<GoogleMapController> _controller = Completer();
  final CameraPosition _initialCameraPosition = const CameraPosition(
    target: LatLng(28.527582, 77.0688971),
    zoom: 16,
  );

  final BitmapDescriptor defaultIcon =
      BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueRed);

  final List<Marker> allMarkers = [];

  @override
  Widget build(BuildContext context) {
    return GetBuilder<MapViewController>(
        init: mapcontroller,
        builder: (controller) {
           return SizedBox(
              width: double.infinity,
              height: double.infinity,
              child: Obx(() => GoogleMap(
            myLocationButtonEnabled: true,
            markers:Set<Marker>.of(allMarkers),
            mapType: MapType.normal,
            initialCameraPosition: _initialCameraPosition,
            onMapCreated: (GoogleMapController gmcontroller) {
              _controller.complete(gmcontroller);
              gmcontroller.setMapStyle(controller.loadMapStyle());
            },
          )),
            ),
        });
  }

  getMarkers() {
    //get markers from controller
    var realdata = mapcontroller.realtimeList;

    realdata.asMap().forEach((key, value) {
      var _marker = Marker(
          consumeTapEvents: true,
          markerId: MarkerId(key.toString()),
          position: LatLng(
              double.parse(value.latitude), double.parse(value.longitude)),
          onTap: () {
            //do something here
          });

      allMarkers.add(_marker);
    });
  }
}

And my controller looks like this.

import 'package:flutter/services.dart';
import 'package:get/get.dart';
import '../../Models/model_realtime.dart';
import '../../Providers/common_api_provider.dart';

class MapViewController extends GetxController {
  var isLoading = false.obs;
  var realtimeList = <ModelRealtime>[].obs;

  @override
  void onInit() {
    fetchRealtimeData();
    super.onInit();
  }

  void fetchRealtimeData() async {
    try {
      isLoading(true);
      var realtime = await CommonApiProvider.realTimeData();
      if (realtime != null) {
        realtimeList.value = realtime;
      }
    } catch (e) {
      isLoading(false);
      // ignore: avoid_print
      print(e);
      rethrow;
    } finally {
      isLoading(false);
    }
  }

  loadMapStyle() async {
    String style = await rootBundle.loadString("assets/map_style.json");
    return style;
  }
}

These codes work pretty well, but it seems to reload/refresh Googlemap everytime new data arrives. How do I update markers' position only everytime the new latitude, longitude updated in the database without reloading/refreshing Googlemap?

Thanks

Lancaster answered 27/12, 2021 at 15:9 Comment(0)
V
7

You are initializing allMarkers list inside view, that's why you need to manually refresh the page in order to display markers on the map.

Initialize allMarkers inside MapViewController

List<Marker> allMarkers = <Marker>[].obs; // Inside Map View Controller

Then, in Google map widget replace marker property

Obx(() => GoogleMap(
            myLocationButtonEnabled: true,
            markers:Set<Marker>.of(controller.allMarkers), // <====== Update
            mapType: MapType.normal,
            initialCameraPosition: _initialCameraPosition,
            onMapCreated: (GoogleMapController gmcontroller) {
              _controller.complete(gmcontroller);
              gmcontroller.setMapStyle(controller.loadMapStyle());
            },
          ))

And in the getMarkers function

getMarkers() {
    // Add this line. Create map view controller object
    final MapViewController _controller = Get.find(); // <======= Add
    //get markers from controller
    var realdata = mapcontroller.realtimeList;

    realdata.asMap().forEach((key, value) {
      var _marker = Marker(
          consumeTapEvents: true,
          markerId: MarkerId(key.toString()),
          position: LatLng(
              double.parse(value.latitude), double.parse(value.longitude)),
          onTap: () {
            //do something here
          });

      _controller.allMarkers.add(_marker); // <===== Update
      _controller.update() // <=== Add, because you are using GetBuilder
    });
  }
}
Veratridine answered 28/12, 2021 at 0:50 Comment(7)
Thanks for the reply! won't Obx( () -> GoogleMap (... refreshes/reloads Googlemap everytime new marker data comes?Lancaster
Also what if i move getMarkers() method on controller itself?Lancaster
@Lancaster Actually you don't need to wrap Google map widget inside Obx because Google map already wrap in Get builder so using Obx at this stage is unnecessary and yeah whenever change received by builder it will re render it's childVeratridine
@Lancaster And moving getMarkers inside controller is a recommend way. If you have controller for specific screen then you should write all the functionalities related to the screen inside controllerVeratridine
Isn't there a way to prevent re-rendering of google map? The changes occurs only in Marker's position, so it is not a good idea to re-render whole map. And google charges amount for every time map is reloaded i think.Lancaster
I don't think there is a way to prevent re-rendering because Getx reconstruct child if change occur actually. You can read more here: state managementVeratridine
@Lancaster There aren't any charges for loading map in application. You can check more: usage and billingVeratridine

© 2022 - 2024 — McMap. All rights reserved.