[google_maps_flutter] Android: only destroy mapView once (#2772)
diff --git a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md
index 66ca6fe..0be2d8f 100644
--- a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md
+++ b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 0.5.28+1
+
+* Android: Make sure map view only calls onDestroy once.
+* Android: Fix a memory leak regression caused in `0.5.26+4`.
+
## 0.5.28
* Android: Add liteModeEnabled option.
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 40cce49..58e8bb0 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
@@ -71,7 +71,7 @@
private final AtomicInteger activityState;
private final MethodChannel methodChannel;
private final GoogleMapOptions options;
- private final MapView mapView;
+ @Nullable private MapView mapView;
private GoogleMap googleMap;
private boolean trackCameraPosition = false;
private boolean myLocationEnabled = false;
@@ -534,6 +534,7 @@
disposed = true;
methodChannel.setMethodCallHandler(null);
setGoogleMapListener(null);
+ destroyMapViewIfNecessary();
getApplication().unregisterActivityLifecycleCallbacks(this);
}
@@ -618,7 +619,7 @@
if (disposed || activity.hashCode() != getActivityHashCode()) {
return;
}
- mapView.onDestroy();
+ destroyMapViewIfNecessary();
}
// DefaultLifecycleObserver and OnSaveInstanceStateListener
@@ -668,7 +669,7 @@
if (disposed) {
return;
}
- mapView.onDestroy();
+ destroyMapViewIfNecessary();
}
@Override
@@ -891,6 +892,14 @@
}
}
+ private void destroyMapViewIfNecessary() {
+ if (mapView == null) {
+ return;
+ }
+ mapView.onDestroy();
+ mapView = null;
+ }
+
public void setIndoorEnabled(boolean indoorEnabled) {
this.indoorEnabled = indoorEnabled;
}
diff --git a/packages/google_maps_flutter/google_maps_flutter/example/android/app/build.gradle b/packages/google_maps_flutter/google_maps_flutter/example/android/app/build.gradle
index 16e93d9..786c784 100644
--- a/packages/google_maps_flutter/google_maps_flutter/example/android/app/build.gradle
+++ b/packages/google_maps_flutter/google_maps_flutter/example/android/app/build.gradle
@@ -51,14 +51,24 @@
signingConfig signingConfigs.debug
}
}
+
+ testOptions {
+ unitTests {
+ includeAndroidResources = true
+ }
+ }
+
+ dependencies {
+ testImplementation 'junit:junit:4.12'
+ androidTestImplementation 'androidx.test:runner:1.1.1'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
+ testImplementation 'androidx.test:core:1.2.0'
+ testImplementation "org.robolectric:robolectric:4.3.1"
+ testImplementation 'org.mockito:mockito-core:3.2.4'
+ testImplementation 'com.google.android.gms:play-services-maps:17.0.0'
+ }
}
flutter {
source '../..'
}
-
-dependencies {
- testImplementation 'junit:junit:4.12'
- androidTestImplementation 'androidx.test:runner:1.1.1'
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
-}
diff --git a/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/test/java/io/flutter/plugins/googlemaps/GoogleMapControllerTest.java b/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/test/java/io/flutter/plugins/googlemaps/GoogleMapControllerTest.java
new file mode 100644
index 0000000..8401a38
--- /dev/null
+++ b/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/test/java/io/flutter/plugins/googlemaps/GoogleMapControllerTest.java
@@ -0,0 +1,64 @@
+package io.flutter.plugins.googlemaps;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.app.Application;
+import android.content.Context;
+import androidx.lifecycle.LifecycleOwner;
+import androidx.test.core.app.ApplicationProvider;
+import com.google.android.gms.maps.GoogleMap;
+import io.flutter.plugin.common.BinaryMessenger;
+import io.flutter.view.FlutterMain;
+import java.util.concurrent.atomic.AtomicInteger;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class GoogleMapControllerTest {
+
+ private Context context;
+ private Application application;
+ private GoogleMapController googleMapController;
+
+ @Mock BinaryMessenger mockMessenger;
+ @Mock GoogleMap mockGoogleMap;
+ @Mock LifecycleOwner lifecycleOwner;
+
+ @BeforeClass()
+ public static void BeforeClass() {
+ FlutterMain.setIsRunningInRobolectricTest(true);
+ }
+
+ @Before
+ public void before() {
+ MockitoAnnotations.initMocks(this);
+ context = ApplicationProvider.getApplicationContext();
+ application = ApplicationProvider.getApplicationContext();
+ googleMapController =
+ new GoogleMapController(
+ 0, context, new AtomicInteger(1), mockMessenger, application, null, null, 0, null);
+ googleMapController.init();
+ }
+
+ @Test
+ public void DisposeReleaseTheMap() throws InterruptedException {
+ googleMapController.onMapReady(mockGoogleMap);
+ assertTrue(googleMapController != null);
+ googleMapController.dispose();
+ assertNull(googleMapController.getView());
+ }
+
+ @Test
+ public void OnDestroyReleaseTheMap() throws InterruptedException {
+ googleMapController.onMapReady(mockGoogleMap);
+ assertTrue(googleMapController != null);
+ googleMapController.onDestroy(lifecycleOwner);
+ assertNull(googleMapController.getView());
+ }
+}
diff --git a/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
new file mode 100644
index 0000000..1f0955d
--- /dev/null
+++ b/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
@@ -0,0 +1 @@
+mock-maker-inline
diff --git a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml
index 4b30226..6214086 100644
--- a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml
+++ b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml
@@ -1,7 +1,7 @@
name: google_maps_flutter
description: A Flutter plugin for integrating Google Maps in iOS and Android applications.
homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter/google_maps_flutter
-version: 0.5.28
+version: 0.5.28+1
dependencies:
flutter: