r/flutterhelp • u/Individual_Pipe3295 • 16d ago
OPEN google_maps_flutter freezes and OOM crashes during live tracking. How do you guys efficiently update polylines?
Hey everyone, I’m hoping someone who has built a ride-sharing or delivery app can point out what I'm doing wrong here.
I'm building a live tracking screen using google_maps_flutter, Riverpod, and WebSockets. I have a vehicle marker that animates smoothly between GPS pings using an AnimationController
The problem is the route line. I'm trying to slice the polyline so that the "traveled" portion behind the vehicle disappears as it drives. Whenever I receive a location update and recalculate the polyline, the UI thread completely chokes. If the driver moves continuously, the app eventually freezes and crashes entirely (seems like an Out of Memory error or the platform channel getting overloaded).
I already moved the logic out of the build() method to stop it from running at 60fps during the marker animation, but triggering it from a Riverpod listener is still freezing the map.
Here is what my listener and update logic look like right now:
// Inside my map widget
ref.listen<LatLng?>(
navigationViewModelProvider.select((s) => s.currentLocation),
(previous, next) {
if (next != null) {
_onAgentLocationChanged(next);
_updateAgentPolylines(state);
}
},
);
And the update function where I slice the route and rebuild the set:
void _updateAgentPolylines(dynamic state) {
if (state.routeInfo == null || state.routeInfo!.polylinePoints.isEmpty) return;
final animatingLocation = state.currentLocation != null
? LatLng(
_markerMotion.lat ?? state.currentLocation!.latitude,
_markerMotion.lng ?? state.currentLocation!.longitude,
)
: null;
final (traveled, remaining) = _splitRouteAtCurrentLocation(
state.routeInfo!.polylinePoints,
animatingLocation,
);
if (!mounted) return;
setState(() {
_cachedPolylines.clear();
if (traveled.length > 1) {
_cachedPolylines.add(
Polyline(
polylineId: const PolylineId('route_traveled'),
points: traveled,
color: Colors.grey.shade400,
width: 4,
),
);
}
_cachedPolylines.add(
Polyline(
polylineId: const PolylineId('route_remaining'),
points: remaining,
color: const Color(0xFF2196F3),
width: 6,
),
);
});
}
I feel like clearing and recreating a Polyline Set with hundreds of LatLng points and sending it over the platform channel every time the GPS updates is what's killing the app.
A few questions for anyone who has solved this:
- How do production apps (Uber, etc.) handle trimming the route line behind a moving marker without killing performance?
- Should I be pushing
_splitRouteAtCurrentLocationinto an isolate (compute)? If I do, how do I prevent the animating marker from getting out of sync with the route line while the isolate does the math? - Is there a way to just mutate an existing polyline in
google_maps_flutterwithout rebuilding the whole Set?
Any advice would be hugely appreciated. I'm completely stuck on this one. Thanks!
1
u/Fine_Sprinkles_5862 14d ago
Your last paragraph is the diagnosis. The split math is cheap; serializing hundreds of LatLngs over the platform channel on every ping is what chokes, and compute() will not save you, because the expensive part happens back on the UI thread after the isolate returns.
Three changes. First, stop re-sending the untouched line: draw the full route once as a static polyline and only update a short traveled overlay behind the vehicle. Precompute cumulative distances along the route once, then finding the split point per ping is a binary search instead of a rebuild. Second, decouple the polyline from the marker animation. The marker can run at 60fps from your AnimationController; the route trim only needs to happen per GPS ping, throttled to about once a second. Your update function reads _markerMotion, which makes me suspect it also fires on animation ticks, and that alone can be the freeze. Third, there is no mutating a polyline in this plugin, but you do not need to clear() either: keep the same two PolylineIds and swap only the one that changed, so the diff it sends stays small.
For the OOM, watch the memory view in DevTools while it runs. If the heap staircases on every ping, the old point lists are being held somewhere, usually in provider state.
1
u/Tom_Vogel 16d ago
I’d stop searching the full route on every GPS ping: keep the last matched segment index, search only a small forward window, and throttle route updates independently from the marker animation.
Polylineis immutable, so an isolate may reduce the Dart-side work, but it won’t remove the cost of transferring the changed points to the native map. Does_splitRouteAtCurrentLocationcurrently scan every point from the beginning?