I'm building an app that uses utsmannn implementation of osmdroid and im trying to take a screenshot of the map similar to this question's answer but when I try to get a mapView instance using overlayManagerState.getMap() I get llegalStateException: Invalid Map attached! which could mean the map instance was null or haven't loaded correctly
@Composable
fun TrackerMap(
modifier: Modifier = Modifier,
isRunFinished: Boolean,
currentLocation: Location?,
locations: List<List<LocationTimestamp>>,
onSnapshot: (Bitmap) -> Unit
) {
var createSnapshotJob: Job? = remember {
null
}
var triggerCapture by remember {
mutableStateOf(true)
}
var mapReady by remember { mutableStateOf(false) } // Track map readiness
LaunchedEffect(key1 = mapReady) {
Timber.e("map is ready!")
}
val context = LocalContext.current
val cameraState = rememberCameraState {
zoom = 17.0
}
LaunchedEffect(currentLocation, isRunFinished) {
if (currentLocation != null && !isRunFinished) {
cameraState.geoPoint = GeoPoint(currentLocation.lat, currentLocation.long)
}
}
val overlayManagerState = rememberOverlayManagerState()
val mapInstance: MapView? = null
var mapProperties by remember {
mutableStateOf(DefaultMapProperties)
}
SideEffect {
mapProperties = mapProperties
.copy(isTilesScaledToDpi = true)
.copy(tileSources = TileSourceFactory.MAPNIK)
.copy(isEnableRotationGesture = false)
.copy(isFlingEnable = false)
.copy(zoomButtonVisibility = ZoomButtonVisibility.NEVER)
}
OpenStreetMap(
modifier = modifier.fillMaxSize(),
cameraState = cameraState,
properties = mapProperties,
overlayManagerState = overlayManagerState,
onFirstLoadListener = {
val copyright = CopyrightOverlay(context)
overlayManagerState.overlayManager.add(copyright)
}
) {
RunikPolylines(locations = locations)
}
LaunchedEffect(isRunFinished, triggerCapture, createSnapshotJob, mapReady) {
var mapView : MapView? = null // Get MapView instance
if (isRunFinished && triggerCapture && createSnapshotJob == null && mapView == null && mapReady) {
triggerCapture = false // Prevent multiple captures
createSnapshotJob = GlobalScope.launch {
var retries = 1000 // Try 10 times max
while (mapView == null && retries > 0) {
try {
mapView = overlayManagerState.getMap()
} catch (e: Exception) {
e.printStackTrace()
}
if (mapView == null) {
retries--
kotlinx.coroutines.delay(500) // Wait 500ms before retrying
}
}
mapView?.let { map ->
val bitmap = captureMapScreenshot(map)
onSnapshot(bitmap) // Pass the Bitmap to onSnapshot callback
}
}
}
}
}
/* Captures the MapView as a Bitmap */
private fun captureMapScreenshot(mapView: MapView): Bitmap {
val bitmap = createBitmap(mapView.width, mapView.height)
val canvas = Canvas(bitmap)
mapView.draw(canvas)
return bitmap
}
note : after my main composabe (OpenStreetMap Composable) i have a LaunchedEffect block that handles the screenshot process
note : I want this app to be fully compose that's why I'm using utsmannn library documentation
what I tried so far :
- tried delaying the getMap() call (to make sure the map is setup fully)
- tried looping over getMap() for 1000 times (500ms interval = 500s wait time in total)
- tried calling getMap() inside of onFirstLoadListener block
every try has resulted in -> llegalStateException: Invalid Map attached!