Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 22 additions & 15 deletions src/main/java/com/mapconductor/mapbox/MapboxMapView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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()
}
},
Expand Down Expand Up @@ -221,27 +229,26 @@ 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 {
lifecycle.removeObserver(observer)
}
}
},
// 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()
}
},
)
}

Expand Down
6 changes: 4 additions & 2 deletions src/main/java/com/mapconductor/mapbox/MapboxViewStateImpl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ class MapboxViewState(
cameraPosition: MapCameraPosition = MapCameraPosition.Default,
) : MapViewState<MapboxDesignType>(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

Expand All @@ -35,7 +38,6 @@ class MapboxViewState(
get() = _mapDesignType

internal fun setController(controller: MapboxMapViewControllerInterface) {
this.controller = controller
attachController(controller)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
}

Expand Down
Loading