summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorŁukasz Paczos <lukasz.paczos@mapbox.com>2018-05-22 20:18:26 +0200
committerŁukasz Paczos <lukasz.paczos@mapbox.com>2018-05-22 20:44:19 +0200
commit428ed71f79a2bf46e0f5f33cb9ab4dcc48e11c79 (patch)
tree858ac8f8ca031f65343374088b7bf9bb4af659d0
parentd8563881c0ee4f62e2f61ce6617ecbf1491ad28b (diff)
downloadqtlocation-mapboxgl-upstream/lp-lifecycle-components.tar.gz
[android] - unregister observers when destroying the map to prevent leaksupstream/lp-lifecycle-components
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapFragment.java3
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapSettings.java36
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java11
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/SupportMapFragment.java3
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java34
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/WidgetUpdater.java2
7 files changed, 80 insertions, 11 deletions
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapFragment.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapFragment.java
index 2cd8e9245e..dfaccbe7fc 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapFragment.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapFragment.java
@@ -24,7 +24,8 @@ import java.util.List;
* </p>
* <p>
* If you are planning on using multiple MapView instances in one lifecycle
- * you have to specify a unique ID for each instance with {@link MapboxMapOptions#setMapId(String)} or in xml attributes.
+ * you have to specify a unique ID for each instance with {@link MapboxMapOptions#setMapId(String)}
+ * or in the xml attributes.
* </p>
* <p>
* To get a reference to the MapView, use {@link #getMapAsync(OnMapReadyCallback)}}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapSettings.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapSettings.java
index 8a64937bf4..6b7c055c7d 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapSettings.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapSettings.java
@@ -1,7 +1,10 @@
package com.mapbox.mapboxsdk.maps;
+import android.arch.lifecycle.LifecycleOwner;
+import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.MutableLiveData;
import android.arch.lifecycle.ViewModel;
+import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
@@ -9,6 +12,12 @@ import android.text.TextUtils;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.constants.Style;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import timber.log.Timber;
+
/**
* Internal class used to manage map settings.
*/
@@ -119,4 +128,31 @@ public final class MapSettings extends ViewModel {
public void setApiBaseUrl(String apiBaseUrl) {
this.apiBaseUrl.setValue(apiBaseUrl);
}
+
+ void onMapDestroy(@NonNull Context context) {
+ clearObservers((LifecycleOwner) context);
+ }
+
+ private void clearObservers(@NonNull LifecycleOwner lifecycleOwner) {
+ try {
+ Field[] fields = this.getClass().getDeclaredFields();
+ Method method = LiveData.class.getDeclaredMethod("removeObservers", LifecycleOwner.class);
+ for (Field field : fields) {
+ Class type = field.getType();
+ if (type == MutableLiveData.class) {
+ Object value = field.get(this);
+ method.invoke(value, lifecycleOwner);
+ }
+ }
+ } catch (NoSuchMethodException ex) {
+ Timber.e("Unable to clear %s observers, %s.", this.getClass(), ex.getClass().getSimpleName());
+ ex.printStackTrace();
+ } catch (IllegalAccessException ex) {
+ Timber.e("Unable to clear %s observers, %s.", this.getClass(), ex.getClass().getSimpleName());
+ ex.printStackTrace();
+ } catch (InvocationTargetException ex) {
+ Timber.e("Unable to clear %s observers, %s.", this.getClass(), ex.getClass().getSimpleName());
+ ex.printStackTrace();
+ }
+ }
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java
index edd93f6ae7..34cc2ed59e 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java
@@ -73,7 +73,8 @@ import static com.mapbox.mapboxsdk.maps.widgets.CompassView.TIME_WAIT_IDLE;
* </p>
* <p>
* If you are planning on using multiple MapView instances in one lifecycle
- * you have to specify a unique ID for each instance with {@link MapboxMapOptions#setMapId(String)} or in xml attributes.
+ * you have to specify a unique ID for each instance with {@link MapboxMapOptions#setMapId(String)}
+ * or in the xml attributes.
* </p>
* <p>
* Use of {@code MapView} requires a Mapbox API access token.
@@ -141,8 +142,8 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback {
}
if (!(context instanceof FragmentActivity)) {
- throw new IllegalArgumentException("You need to instantiate MapView from FragmentActivity context. " +
- "If your LayoutInflater works with a different context try creating MapView programmatically.");
+ throw new IllegalArgumentException("You need to instantiate MapView from FragmentActivity context. "
+ + "If your LayoutInflater works with a different context try creating MapView programmatically.");
}
mapboxMapOptions = options;
@@ -435,7 +436,9 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback {
destroyed = true;
onMapChangedListeners.clear();
mapCallback.clearOnMapReadyCallbacks();
- uiSettings.onMapDestroy();
+
+ uiSettings.onMapDestroy(getContext());
+ mapSettings.onMapDestroy(getContext());
if (nativeMapView != null && hasSurface) {
// null when destroying an activity programmatically mapbox-navigation-android/issues/503
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/SupportMapFragment.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/SupportMapFragment.java
index 3b30424c63..5ab977d5d4 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/SupportMapFragment.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/SupportMapFragment.java
@@ -24,7 +24,8 @@ import java.util.List;
* </p>
* <p>
* If you are planning on using multiple MapView instances in one lifecycle
- * you have to specify a unique ID for each instance with {@link MapboxMapOptions#setMapId(String)} or in xml attributes.
+ * you have to specify a unique ID for each instance with {@link MapboxMapOptions#setMapId(String)}
+ * or in the xml attributes.
* </p>
* <p>
* To get a reference to the MapView, use {@link #getMapAsync(OnMapReadyCallback)}}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java
index ea0665d372..96018bb4c0 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java
@@ -1,5 +1,7 @@
package com.mapbox.mapboxsdk.maps;
+import android.arch.lifecycle.LifecycleOwner;
+import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.MutableLiveData;
import android.arch.lifecycle.ViewModel;
import android.content.Context;
@@ -17,6 +19,12 @@ import com.mapbox.mapboxsdk.R;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.utils.ColorUtils;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import timber.log.Timber;
+
/**
* Settings for the user interface of a MapboxMap. To obtain this interface, call getUiSettings().
*/
@@ -997,8 +1005,32 @@ public final class UiSettings extends ViewModel {
* Method used to cleanup resources that might leak during configuration change,
* like deprecated {@link #setAttributionDialogManager(AttributionDialogManager)} or {@link #getWidth()}.
*/
- void onMapDestroy() {
+ void onMapDestroy(@NonNull Context context) {
setAttributionDialogManager(null);
projection = null;
+ clearObservers((LifecycleOwner) context);
+ }
+
+ private void clearObservers(@NonNull LifecycleOwner lifecycleOwner) {
+ try {
+ Field[] fields = this.getClass().getDeclaredFields();
+ Method method = LiveData.class.getDeclaredMethod("removeObservers", LifecycleOwner.class);
+ for (Field field : fields) {
+ Class type = field.getType();
+ if (type == MutableLiveData.class) {
+ Object value = field.get(this);
+ method.invoke(value, lifecycleOwner);
+ }
+ }
+ } catch (NoSuchMethodException ex) {
+ Timber.e("Unable to clear %s observers, %s.", this.getClass(), ex.getClass().getSimpleName());
+ ex.printStackTrace();
+ } catch (IllegalAccessException ex) {
+ Timber.e("Unable to clear %s observers, %s.", this.getClass(), ex.getClass().getSimpleName());
+ ex.printStackTrace();
+ } catch (InvocationTargetException ex) {
+ Timber.e("Unable to clear %s observers, %s.", this.getClass(), ex.getClass().getSimpleName());
+ ex.printStackTrace();
+ }
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java
index 712e137238..5b5999a4a5 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java
@@ -1,12 +1,10 @@
package com.mapbox.mapboxsdk.maps.widgets;
import android.annotation.SuppressLint;
-import android.arch.lifecycle.ViewModelProviders;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
import android.support.annotation.UiThread;
-import android.support.v4.app.FragmentActivity;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.ViewPropertyAnimatorCompat;
import android.support.v4.view.ViewPropertyAnimatorListenerAdapter;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/WidgetUpdater.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/WidgetUpdater.java
index 0f3dbac309..523411b1f5 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/WidgetUpdater.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/WidgetUpdater.java
@@ -1,11 +1,9 @@
package com.mapbox.mapboxsdk.maps.widgets;
import android.arch.lifecycle.LifecycleOwner;
-import android.arch.lifecycle.ViewModelProviders;
import android.content.Context;
import android.graphics.Color;
import android.support.annotation.NonNull;
-import android.support.v4.app.FragmentActivity;
import android.support.v4.content.ContextCompat;
import android.view.View;
import android.widget.ImageView;