From d38827c7cb16b31dca5a3f9408e72798ad74e8fc Mon Sep 17 00:00:00 2001 From: Masashi Katsumata Date: Sat, 7 Nov 2026 13:16:50 -0800 Subject: [PATCH 1/3] Destroy the WebView when the map leaves the composition The controller was destroyed but the WebView was not, so its renderer and JS bridge kept the controller with every overlay. It is now detached, loses the bridge and is destroyed. --- src/main/java/com/mapconductor/longdo/LongdoMapView.kt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/java/com/mapconductor/longdo/LongdoMapView.kt b/src/main/java/com/mapconductor/longdo/LongdoMapView.kt index 445220f..294ecd6 100644 --- a/src/main/java/com/mapconductor/longdo/LongdoMapView.kt +++ b/src/main/java/com/mapconductor/longdo/LongdoMapView.kt @@ -530,6 +530,14 @@ fun LongdoMapSurface( onDispose { moveDispatcher.cancel() controller.destroy() + // The WebView is the map. Not destroyed, it keeps its renderer and + // the JS bridge, and through them the controller with every overlay. + // This runs for a configuration change too: the old Activity's + // WebView is never shown again (the state is what survives). + (longdoMap.parent as? ViewGroup)?.removeView(longdoMap) + longdoMap.removeJavascriptInterface(BRIDGE_NAME) + longdoMap.stopLoading() + longdoMap.destroy() } } } From a9479f2cbf970ccdb4a6160162e397a2952b8d24 Mon Sep 17 00:00:00 2001 From: Masashi Katsumata Date: Sat, 7 Nov 2026 16:20:26 -0800 Subject: [PATCH 2/3] Read the controller through the state base, which MapViewBase clears The state kept its own controller field, set on attach and never cleared, so a state the app keeps held the destroyed controller and every overlay of the old map. It now reads the base's attached controller, which MapViewBase detaches when the map is torn down. --- .../java/com/mapconductor/longdo/LongdoViewStateImpl.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/mapconductor/longdo/LongdoViewStateImpl.kt b/src/main/java/com/mapconductor/longdo/LongdoViewStateImpl.kt index 0e689e7..fa86655 100644 --- a/src/main/java/com/mapconductor/longdo/LongdoViewStateImpl.kt +++ b/src/main/java/com/mapconductor/longdo/LongdoViewStateImpl.kt @@ -38,7 +38,10 @@ class LongdoViewState( LongdoViewStateInterface { private var _mapDesignType by mutableStateOf(mapDesignType) - private var controller: LongdoMapViewController? = null + // Read through the base so that letting go of the controller there (MapViewBase + // does it when the map is torn down) leaves nothing behind here. + private val controller: LongdoMapViewController? + get() = attachedMapController as? LongdoMapViewController override var mapDesignType: LongdoMapDesignTypeInterface get() = _mapDesignType @@ -49,7 +52,6 @@ class LongdoViewState( /** MapView 生成時にコントローラを紐付ける。 */ fun setController(controller: LongdoMapViewController) { - this.controller = controller // 初期カメラは LongdoMap.LOCATION として地図読み込み前に渡すので、接続時には移動しない。 attachController(controller, moveToInitialCamera = false) } From 4e3cee430beab69bc0d7e9d7721c8c107078166d Mon Sep 17 00:00:00 2001 From: Masashi Katsumata Date: Sat, 7 Nov 2026 17:21:31 -0800 Subject: [PATCH 3/3] Detach the controller from the state when the map is disposed This provider does not go through MapViewBase, which does it for the others; a state the app keeps held the destroyed controller and its overlays. --- src/main/java/com/mapconductor/longdo/LongdoMapView.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/com/mapconductor/longdo/LongdoMapView.kt b/src/main/java/com/mapconductor/longdo/LongdoMapView.kt index 294ecd6..35ec922 100644 --- a/src/main/java/com/mapconductor/longdo/LongdoMapView.kt +++ b/src/main/java/com/mapconductor/longdo/LongdoMapView.kt @@ -530,6 +530,9 @@ fun LongdoMapSurface( onDispose { moveDispatcher.cancel() controller.destroy() + // No MapViewBase here to do it: the state (which the app keeps) must + // not hold on to the destroyed controller and its overlays. + state.detachController(controller) // The WebView is the map. Not destroyed, it keeps its renderer and // the JS bridge, and through them the controller with every overlay. // This runs for a configuration change too: the old Activity's