-
Notifications
You must be signed in to change notification settings - Fork 166
Open
Labels
triage meI really want to be triaged.I really want to be triaged.type: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.Error or flaw in code with unintended results or allowing sub-optimal usage patterns.
Description
We have started noticing an increasing number of Crash reports on Firebase Crashlytics since we bumped our com.google.maps.android:maps-compose version from 6.10.0 to 6.12.0 and 6.12.1
They're only happening on certain devices. The stacktrace is obfuscated, so there isn't a lot of data here, but generally it goes like this:
Fatal Exception: java.lang.IllegalStateException: Method addObserver must be called on the main thread
at m.abg.i(:com.google.android.gms.policy_maps_core_dynamite@233610105@233610102065.573949206.573949206:21)
at m.abg.b(:com.google.android.gms.policy_maps_core_dynamite@233610105@233610102065.573949206.573949206:3)
at m.dba.e(:com.google.android.gms.policy_maps_core_dynamite@233610105@233610102065.573949206.573949206:96)
at com.google.android.gms.maps.internal.CreatorImpl.c(:com.google.android.gms.policy_maps_core_dynamite@233610105@233610102065.573949206.573949206:908)
at com.google.android.gms.maps.internal.CreatorImpl.logInitialization(:com.google.android.gms.policy_maps_core_dynamite@233610105@233610102065.573949206.573949206:16)
at com.google.android.gms.maps.internal.i.bp(:com.google.android.gms.policy_maps_core_dynamite@233610105@233610102065.573949206.573949206:75)
at m.bbf.onTransact(:com.google.android.gms.policy_maps_core_dynamite@233610105@233610102065.573949206.573949206:21)
at android.os.Binder.transact(Binder.java:1219)
at com.google.android.gms.internal.maps.zza.zzc(com.google.android.gms:play-services-maps@@19.2.0:2)
at com.google.android.gms.maps.internal.zze.zzm(com.google.android.gms:play-services-maps@@19.2.0:4)
at com.google.android.gms.maps.MapsInitializer.initialize(com.google.android.gms:play-services-maps@@19.2.0:12)
at com.google.android.gms.maps.MapsInitializer.initialize(com.google.android.gms:play-services-maps@@19.2.0:1)
at com.google.maps.android.compose.internal.DefaultGoogleMapsInitializer$initialize$3.invokeSuspend(DefaultGoogleMapsInitializer.java:146)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:34)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:100)
at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.java:124)
at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:89)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.java:586)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:820)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:717)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:704)
Device here was Samsung Galaxy M35 5G running Android 14.
Another from Samsung Galaxy A16 running Android 14:
Fatal Exception: java.lang.IllegalStateException: Method addObserver must be called on the main thread
at m.acj.k(:com.google.android.gms.policy_maps_core_dynamite@241110203@241110201042.615149234.615149234:21)
at m.acj.b(:com.google.android.gms.policy_maps_core_dynamite@241110203@241110201042.615149234.615149234:3)
at m.dec.e(:com.google.android.gms.policy_maps_core_dynamite@241110203@241110201042.615149234.615149234:113)
at com.google.android.gms.maps.internal.CreatorImpl.d(:com.google.android.gms.policy_maps_core_dynamite@241110203@241110201042.615149234.615149234:920)
at com.google.android.gms.maps.internal.CreatorImpl.logInitialization(:com.google.android.gms.policy_maps_core_dynamite@241110203@241110201042.615149234.615149234:60)
at com.google.android.gms.maps.internal.i.bo(:com.google.android.gms.policy_maps_core_dynamite@241110203@241110201042.615149234.615149234:75)
at m.bcw.onTransact(:com.google.android.gms.policy_maps_core_dynamite@241110203@241110201042.615149234.615149234:21)
at android.os.Binder.transact(Binder.java:1219)
at com.google.android.gms.internal.maps.zza.zzc(com.google.android.gms:play-services-maps@@19.2.0:2)
at com.google.android.gms.maps.internal.zze.zzm(com.google.android.gms:play-services-maps@@19.2.0:4)
at com.google.android.gms.maps.MapsInitializer.initialize(com.google.android.gms:play-services-maps@@19.2.0:12)
at com.google.android.gms.maps.MapsInitializer.initialize(com.google.android.gms:play-services-maps@@19.2.0:1)
at com.google.maps.android.compose.internal.DefaultGoogleMapsInitializer$initialize$3.invokeSuspend(DefaultGoogleMapsInitializer.java:146)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:34)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:100)
at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.java:124)
at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:89)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.java:586)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:820)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:717)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:704)
I saw that there were updates to the initializer when bumping the version, so that might be it. We're also using com.google.maps.android:maps-compose-utils in our app.
Steps to reproduce
- Have a Map Screen
- Launch the app on certain devices
Code example
@Composable
fun NearbyDiscoveryFeature() {
val context = LocalContext.current
var location by remember { mutableStateOf<Location?>(null) }
var isLoading by remember { mutableStateOf(true) }
var hasLocationPermission by remember {
mutableStateOf(
context.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
)
}
val locationPermissionLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.RequestPermission(),
onResult = { isGranted ->
hasLocationPermission = isGranted
if (!isGranted) {
isLoading = false
}
}
)
LaunchedEffect(hasLocationPermission) {
if (hasLocationPermission) {
// Simulate a network call to fetch location
delay(1500)
location = createFakeLocation()
isLoading = false
} else {
locationPermissionLauncher.launch(Manifest.permission.ACCESS_FINE_LOCATION)
}
}
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
when {
isLoading -> {
CircularProgressIndicator()
}
hasLocationPermission -> {
LocationMapView(
location = location,
onMapClicked = { /* Handle map click */ }
)
}
else -> {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text(
text = "Location permission is required to use this feature.",
textAlign = TextAlign.Center,
modifier = Modifier.padding(16.dp)
)
Button(onClick = { locationPermissionLauncher.launch(Manifest.permission.ACCESS_FINE_LOCATION) }) {
Text("Grant Permission")
}
}
}
}
}
}
@Composable
fun LocationMapView(
location: Location?,
modifier: Modifier = Modifier,
onMapClicked: () -> Unit,
) {
val cameraPositionState = rememberCameraPositionState {
val targetLocation = location?.let { LatLng(it.latitude, it.longitude) } ?: LatLng(0.0, 0.0)
position = CameraPosition.fromLatLngZoom(
targetLocation,
if (location == null) 1f else 15f
)
}
Box(
modifier = modifier
.clip(RoundedCornerShape(8.dp))
.clickable { onMapClicked() }
) {
GoogleMap(
modifier = Modifier.fillMaxSize(),
cameraPositionState = cameraPositionState,
properties = MapProperties(
isMyLocationEnabled = location != null
),
uiSettings = MapUiSettings(
myLocationButtonEnabled = false,
zoomControlsEnabled = false,
mapToolbarEnabled = false,
scrollGesturesEnabled = false,
compassEnabled = false,
indoorLevelPickerEnabled = false,
rotationGesturesEnabled = false,
scrollGesturesEnabledDuringRotateOrZoom = false,
tiltGesturesEnabled = false,
zoomGesturesEnabled = false,
),
onMapClick = { onMapClicked() },
)
Box(
modifier = Modifier
.fillMaxSize()
.background(
brush = Brush.verticalGradient(
colors = listOf(Color.Transparent, Color.Black),
),
alpha = 0.5f
)
)
Button(
modifier = Modifier
.align(Alignment.BottomStart)
.padding(16.dp),
onClick = { onMapClicked() }
) {
Text("Open Map")
}
}
}
private fun createFakeLocation(): Location {
return Location("fake_provider").apply {
latitude = 34.0522
longitude = -118.2437
}
}
barry-irvine
Metadata
Metadata
Assignees
Labels
triage meI really want to be triaged.I really want to be triaged.type: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.Error or flaw in code with unintended results or allowing sub-optimal usage patterns.