From 6d9567fd98b13ad75ce85e88854135003ec296a5 Mon Sep 17 00:00:00 2001 From: Victor Shcherb Date: Tue, 7 Jul 2015 14:54:02 +0300 Subject: [PATCH] Fix UI memory leak on rotate / Merge with master special tests will be needed of this branch Conflicts: OsmAnd/src/net/osmand/plus/monitoring/OsmandMonitoringPlugin.java OsmAnd/src/net/osmand/plus/osmo/OsMoPlugin.java OsmAnd/src/net/osmand/plus/render/MapRenderRepositories.java --- .../src/net/osmand/plus/OsmandSettings.java | 27 ++++++++---- .../DistanceCalculatorPlugin.java | 4 +- .../monitoring/OsmandMonitoringPlugin.java | 17 +++++++- .../src/net/osmand/plus/osmo/OsMoPlugin.java | 41 ++++++++++++++++--- .../plus/render/MapRenderRepositories.java | 15 ++++--- 5 files changed, 80 insertions(+), 24 deletions(-) diff --git a/OsmAnd/src/net/osmand/plus/OsmandSettings.java b/OsmAnd/src/net/osmand/plus/OsmandSettings.java index 22d395776b..5ff2b4d0cc 100644 --- a/OsmAnd/src/net/osmand/plus/OsmandSettings.java +++ b/OsmAnd/src/net/osmand/plus/OsmandSettings.java @@ -3,6 +3,7 @@ package net.osmand.plus; import java.io.File; import java.io.IOException; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; @@ -67,22 +68,28 @@ public class OsmandSettings { } private abstract class PreferenceWithListener implements OsmandPreference { - private List> l = null; + private List>> l = null; @Override public void addListener(StateChangedListener listener) { if(l == null) { - l = new LinkedList>(); + l = new LinkedList>>(); } - if(!l.contains(listener)) { - l.add(listener); + if(!l.contains(new WeakReference>(listener))) { + l.add(new WeakReference>(listener)); } } public void fireEvent(T value){ if (l != null) { - for (StateChangedListener t : l) { - t.stateChanged(value); + Iterator>> it = l.iterator(); + while(it.hasNext()) { + StateChangedListener t = it.next().get(); + if(t == null) { + it.remove(); + } else { + t.stateChanged(value); + } } } } @@ -90,7 +97,13 @@ public class OsmandSettings { @Override public void removeListener(StateChangedListener listener) { if(l != null) { - l.remove(listener); + Iterator>> it = l.iterator(); + while(it.hasNext()) { + StateChangedListener t = it.next().get(); + if(t == listener) { + it.remove(); + } + } } } } diff --git a/OsmAnd/src/net/osmand/plus/distancecalculator/DistanceCalculatorPlugin.java b/OsmAnd/src/net/osmand/plus/distancecalculator/DistanceCalculatorPlugin.java index f89e5ff43a..e233a31d89 100644 --- a/OsmAnd/src/net/osmand/plus/distancecalculator/DistanceCalculatorPlugin.java +++ b/OsmAnd/src/net/osmand/plus/distancecalculator/DistanceCalculatorPlugin.java @@ -102,7 +102,9 @@ public class DistanceCalculatorPlugin extends OsmandPlugin { if(!mapView.isLayerVisible(distanceCalculatorLayer)) { activity.getMapView().addLayer(distanceCalculatorLayer, 4.5f); } - registerWidget(activity); + if(distanceControl == null) { + registerWidget(activity); + } } else { MapInfoLayer mapInfoLayer = activity.getMapLayers().getMapInfoLayer(); if(distanceCalculatorLayer != null) { diff --git a/OsmAnd/src/net/osmand/plus/monitoring/OsmandMonitoringPlugin.java b/OsmAnd/src/net/osmand/plus/monitoring/OsmandMonitoringPlugin.java index de39398485..e9d682ea24 100644 --- a/OsmAnd/src/net/osmand/plus/monitoring/OsmandMonitoringPlugin.java +++ b/OsmAnd/src/net/osmand/plus/monitoring/OsmandMonitoringPlugin.java @@ -90,6 +90,10 @@ public class OsmandMonitoringPlugin extends OsmandPlugin { @Override public void registerLayers(MapActivity activity) { + registerWidget(activity); + } + + private void registerWidget(MapActivity activity) { MapInfoLayer layer = activity.getMapLayers().getMapInfoLayer(); monitoringControl = createMonitoringControl(activity); @@ -100,8 +104,17 @@ public class OsmandMonitoringPlugin extends OsmandPlugin { @Override public void updateLayers(OsmandMapTileView mapView, MapActivity activity) { - if(monitoringControl == null) { - registerLayers(activity); + if (isActive()) { + if (monitoringControl == null) { + registerWidget(activity); + } + } else { + if (monitoringControl != null) { + MapInfoLayer layer = activity.getMapLayers().getMapInfoLayer(); + layer.removeSideWidget(monitoringControl); + layer.recreateControls(); + monitoringControl = null; + } } } diff --git a/OsmAnd/src/net/osmand/plus/osmo/OsMoPlugin.java b/OsmAnd/src/net/osmand/plus/osmo/OsMoPlugin.java index 78e68ec435..61f363d3d0 100644 --- a/OsmAnd/src/net/osmand/plus/osmo/OsMoPlugin.java +++ b/OsmAnd/src/net/osmand/plus/osmo/OsMoPlugin.java @@ -30,6 +30,7 @@ import net.osmand.plus.osmo.OsMoGroupsStorage.OsMoDevice; import net.osmand.plus.osmo.OsMoService.SessionInfo; import net.osmand.plus.views.MapInfoLayer; import net.osmand.plus.views.OsmandMapLayer.DrawSettings; +import net.osmand.plus.views.OsmandMapTileView; import net.osmand.plus.views.mapwidgets.TextInfoWidget; import net.osmand.util.Algorithms; @@ -169,21 +170,49 @@ public class OsMoPlugin extends OsmandPlugin implements OsMoReactor { super.registerMapContextMenuActions(mapActivity, latitude, longitude, adapter, selectedObj); } + @Override + public void updateLayers(OsmandMapTileView mapView, MapActivity activity) { + if(isActive()) { + if(olayer == null) { + registerLayers(activity); + } + if(osmoControl == null) { + registerSideWidget(activity); + } + } else { + MapInfoLayer layer = activity.getMapLayers().getMapInfoLayer(); + if (layer != null && osmoControl != null) { + layer.removeSideWidget(osmoControl); + osmoControl = null; + layer.recreateControls(); + } + if(olayer != null) { + activity.getMapView().removeLayer(olayer); + olayer = null; + } + } + } + @Override public void registerLayers(MapActivity activity) { super.registerLayers(activity); - MapInfoLayer layer = activity.getMapLayers().getMapInfoLayer(); - osmoControl = createOsMoControl(activity); - layer.registerSideWidget(osmoControl, - R.drawable.ic_osmo_dark, R.string.osmo_control, "osmo_control", false, 18); - layer.recreateControls(); - + registerSideWidget(activity); if(olayer != null) { activity.getMapView().removeLayer(olayer); } olayer = new OsMoPositionLayer(activity, this); activity.getMapView().addLayer(olayer, 5.5f); } + + private void registerSideWidget(MapActivity activity) { + MapInfoLayer layer = activity.getMapLayers().getMapInfoLayer(); + if (layer != null) { + osmoControl = createOsMoControl(activity); + layer.registerSideWidget(osmoControl, R.drawable.ic_osmo_dark, R.string.osmo_control, "osmo_control", + false, 18); + layer.recreateControls(); + } + } @Override public void mapActivityPause(MapActivity activity) { diff --git a/OsmAnd/src/net/osmand/plus/render/MapRenderRepositories.java b/OsmAnd/src/net/osmand/plus/render/MapRenderRepositories.java index 19257c27ed..abc7118a1a 100644 --- a/OsmAnd/src/net/osmand/plus/render/MapRenderRepositories.java +++ b/OsmAnd/src/net/osmand/plus/render/MapRenderRepositories.java @@ -731,24 +731,23 @@ public class MapRenderRepositories { Bitmap reuse = prevBmp; this.prevBmp = this.bmp; this.prevBmpLocation = this.bmpLocation; - if (reuse != null && reuse.getWidth() == currentRenderingContext.width && reuse.getHeight() == currentRenderingContext.height) { + // necessary for transparent, otherwise 2 times smaller + Config cfg = transparent ? Config.ARGB_8888 : Config.RGB_565; + if (reuse != null && reuse.getWidth() == currentRenderingContext.width && reuse.getHeight() == currentRenderingContext.height && + cfg == reuse.getConfig()) { bmp = reuse; bmp.eraseColor(currentRenderingContext.defaultColor); } else { if(reuse != null){ log.warn(String.format("Create new image ? %d != %d (w) %d != %d (h) ", currentRenderingContext.width, reuse.getWidth(), currentRenderingContext.height, reuse.getHeight())); } - if(transparent) { - // necessary - bmp = Bitmap.createBitmap(currentRenderingContext.width, currentRenderingContext.height, Config.ARGB_8888); - } else { - // better picture ? - bmp = Bitmap.createBitmap(currentRenderingContext.width, currentRenderingContext.height, Config.ARGB_8888); + bmp = Bitmap.createBitmap(currentRenderingContext.width, currentRenderingContext.height, cfg); + if(reuse != null) { + reuse.recycle(); } } this.bmp = bmp; this.bmpLocation = tileRect; - if(nativeLib != null) { renderer.generateNewBitmapNative(currentRenderingContext, nativeLib, cNativeObjects, bmp, renderingReq, notifyList); } else {