diff --git a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md
index 57d24e2196a5..b4fb6622edc2 100644
--- a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md
+++ b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md
@@ -1,5 +1,6 @@
-## NEXT
+## 2.1.6
+* Fixes issue in Flutter v3.0.0 where some updates to the map don't take effect on Android.
* Fixes iOS native unit tests on M1 devices.
* Minor fixes for new analysis options.
diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java
index 9b8810354b8f..2c2287cf59d4 100644
--- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java
+++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java
@@ -12,9 +12,11 @@
import android.graphics.Point;
import android.os.Bundle;
import android.util.Log;
+import android.view.Choreographer;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleOwner;
@@ -109,6 +111,11 @@ public View getView() {
return mapView;
}
+ @VisibleForTesting
+ /*package*/ void setView(MapView view) {
+ mapView = view;
+ }
+
void init() {
lifecycleProvider.getLifecycle().addObserver(this);
mapView.getMapAsync(this);
@@ -126,6 +133,58 @@ private CameraPosition getCameraPosition() {
return trackCameraPosition ? googleMap.getCameraPosition() : null;
}
+ private boolean loadedCallbackPending = false;
+
+ /**
+ * Invalidates the map view after the map has finished rendering.
+ *
+ *
gmscore GL renderer uses a {@link android.view.TextureView}. Android platform views that are
+ * displayed as a texture after Flutter v3.0.0. require that the view hierarchy is notified after
+ * all drawing operations have been flushed.
+ *
+ *
Since the GL renderer doesn't use standard Android views, and instead uses GL directly, we
+ * notify the view hierarchy by invalidating the view.
+ *
+ *
Unfortunately, when {@link GoogleMap.OnMapLoadedCallback} is fired, the texture may not have
+ * been updated yet.
+ *
+ *
To workaround this limitation, wait two frames. This ensures that at least the frame budget
+ * (16.66ms at 60hz) have passed since the drawing operation was issued.
+ */
+ private void invalidateMapIfNeeded() {
+ if (googleMap == null || loadedCallbackPending) {
+ return;
+ }
+ loadedCallbackPending = true;
+ googleMap.setOnMapLoadedCallback(
+ new GoogleMap.OnMapLoadedCallback() {
+ @Override
+ public void onMapLoaded() {
+ loadedCallbackPending = false;
+ postFrameCallback(
+ () -> {
+ postFrameCallback(
+ () -> {
+ if (mapView != null) {
+ mapView.invalidate();
+ }
+ });
+ });
+ }
+ });
+ }
+
+ private static void postFrameCallback(Runnable f) {
+ Choreographer.getInstance()
+ .postFrameCallback(
+ new Choreographer.FrameCallback() {
+ @Override
+ public void doFrame(long frameTimeNanos) {
+ f.run();
+ }
+ });
+ }
+
@Override
public void onMapReady(GoogleMap googleMap) {
this.googleMap = googleMap;
@@ -244,6 +303,7 @@ public void onSnapshotReady(Bitmap bitmap) {
}
case "markers#update":
{
+ invalidateMapIfNeeded();
List