diff --git a/src/main/java/com/mapconductor/mapbox/MapboxMapView.kt b/src/main/java/com/mapconductor/mapbox/MapboxMapView.kt index f2a0f8d..847e722 100644 --- a/src/main/java/com/mapconductor/mapbox/MapboxMapView.kt +++ b/src/main/java/com/mapconductor/mapbox/MapboxMapView.kt @@ -11,9 +11,12 @@ import androidx.compose.ui.platform.LocalContext import androidx.lifecycle.DefaultLifecycleObserver import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.compose.LocalLifecycleOwner +import androidx.lifecycle.findViewTreeLifecycleOwner +import androidx.lifecycle.setViewTreeLifecycleOwner import com.mapbox.maps.MapInitOptions import com.mapbox.maps.MapView import com.mapconductor.compose.map.MapViewBase +import com.mapconductor.compose.map.MapViewLifecycleOwner import com.mapconductor.core.OnCameraMoveHandler import com.mapconductor.core.OnMapEventHandler import com.mapconductor.core.OnMapLoadedHandler @@ -58,7 +61,6 @@ import android.annotation.SuppressLint import android.app.Activity import android.content.Context import android.content.ContextWrapper -import android.view.ViewGroup @SuppressLint("Lifecycle") @Composable @@ -117,6 +119,12 @@ fun MapboxMapView( ) MapView(context, mapOptions).also { + // Mapbox's lifecycle plugin follows the view tree's lifecycle and + // only lets go of the MapView (component callbacks, observers) + // when that lifecycle is destroyed. With the Activity's, every + // MapView the user switched away from would stay until the + // Activity goes, so it gets one of its own; see onDestroyMapView. + it.setViewTreeLifecycleOwner(MapViewLifecycleOwner(lifecycle)) it.onStart() } }, @@ -221,20 +229,6 @@ fun MapboxMapView( // Do not call here to keep the MapView instance // holderRef.value?.mapView?.onPause() } - - @SuppressLint("Lifecycle") - override fun onDestroy(owner: LifecycleOwner) { - val currentHolder = holderRef.value - if (currentHolder != null) { - val activity = context.findActivity() - if (activity?.isChangingConfigurations == true) { - (currentHolder.mapView.parent as? ViewGroup)?.removeView(currentHolder.mapView) - } else { - // Ensure these calls are safe if mapView might be null or already destroyed - currentHolder.mapView.onDestroy() - } - } - } } lifecycle.addObserver(observer) onDispose { @@ -242,6 +236,19 @@ fun MapboxMapView( } } }, + // Ending the MapView's own lifecycle has the lifecycle plugin stop and + // destroy it and unregister what it registered. A MapView left alive + // keeps its renderer and, through its listeners, the controller with + // every overlay. + onDestroyMapView = { mapView -> + val owner = mapView.findViewTreeLifecycleOwner() as? MapViewLifecycleOwner + if (owner != null) { + owner.destroy() + } else { + mapView.onStop() + mapView.onDestroy() + } + }, ) } diff --git a/src/main/java/com/mapconductor/mapbox/MapboxViewStateImpl.kt b/src/main/java/com/mapconductor/mapbox/MapboxViewStateImpl.kt index 1e0adea..57fa0f0 100644 --- a/src/main/java/com/mapconductor/mapbox/MapboxViewStateImpl.kt +++ b/src/main/java/com/mapconductor/mapbox/MapboxViewStateImpl.kt @@ -23,7 +23,10 @@ class MapboxViewState( cameraPosition: MapCameraPosition = MapCameraPosition.Default, ) : MapViewState(cameraPosition), MapboxViewStateInterface { - private var controller: MapboxMapViewControllerInterface? = 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: MapboxMapViewControllerInterface? + get() = attachedMapController as? MapboxMapViewControllerInterface private var _mapDesignType: MapboxDesignType = mapDesignType @@ -35,7 +38,6 @@ class MapboxViewState( get() = _mapDesignType internal fun setController(controller: MapboxMapViewControllerInterface) { - this.controller = controller attachController(controller) } diff --git a/src/main/java/com/mapconductor/mapbox/polygon/MapboxPolygonConductor.kt b/src/main/java/com/mapconductor/mapbox/polygon/MapboxPolygonConductor.kt index d797101..9599813 100644 --- a/src/main/java/com/mapconductor/mapbox/polygon/MapboxPolygonConductor.kt +++ b/src/main/java/com/mapconductor/mapbox/polygon/MapboxPolygonConductor.kt @@ -129,7 +129,10 @@ class MapboxPolygonConductor( } override fun destroy() { - // No native resources to clean up for polygons + // A destroyed conductor can still be referenced (by its map controller, + // or a state that has not let go yet); without this it keeps every entity. + polygonOverlay.polygonManager.clear() + polylineOverlay.polylineManager.clear() } }