google map crashed with instrumentation test
Device: Pixel 5 API 30 sdk version: 2.5.3 & 2.7.2
i've implemented GoogleMap with ComposeView, it's crashing in the instrumentation test case with the following stack trace:
com.google.maps.api.android.lib6.common.apiexception.c: Not on the main thread
at com.google.maps.api.android.lib6.common.m.i(:com.google.android.gms.dynamite_mapsdynamite@[email protected] (150400-0):0)
at com.google.maps.api.android.lib6.common.r.a(:com.google.android.gms.dynamite_mapsdynamite@[email protected] (150400-0):2)
at com.google.maps.api.android.lib6.impl.bj.p(:com.google.android.gms.dynamite_mapsdynamite@[email protected] (150400-0):1)
at com.google.android.gms.maps.internal.i.ba(:com.google.android.gms.dynamite_mapsdynamite@[email protected] (150400-0):186)
at en.onTransact(:com.google.android.gms.dynamite_mapsdynamite@[email protected] (150400-0):4)
at android.os.Binder.transact(Binder.java:1043)
at com.google.android.gms.internal.maps.zza.zzc(com.google.android.gms:play-services-maps@@18.1.0:2)
at com.google.android.gms.maps.internal.zzg.clear(com.google.android.gms:play-services-maps@@18.1.0:2)
at com.google.android.gms.maps.GoogleMap.clear(com.google.android.gms:play-services-maps@@18.1.0:1)
at com.google.maps.android.compose.MapApplier.onClear(MapApplier.kt:46)
at androidx.compose.runtime.AbstractApplier.clear(Applier.kt:213)
at androidx.compose.runtime.CompositionImpl.dispose(Composition.kt:601)
at com.google.maps.android.compose.GoogleMapKt$GoogleMap$10.invokeSuspend(GoogleMap.kt:229)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at androidx.compose.ui.test.ApplyingContinuationInterceptor$SendApplyContinuation.resumeWith(ApplyingContinuationInterceptor.kt:70)
at kotlinx.coroutines.DispatchedTaskKt.resume(DispatchedTask.kt:234)
at kotlinx.coroutines.DispatchedTaskKt.resumeUnconfined(DispatchedTask.kt:190)
at kotlinx.coroutines.DispatchedTaskKt.dispatch(DispatchedTask.kt:161)
at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.kt:397)
at kotlinx.coroutines.CancellableContinuationImpl.cancel(CancellableContinuationImpl.kt:183)
at kotlinx.coroutines.CancellableContinuationImpl.parentCancelled$kotlinx_coroutines_core(CancellableContinuationImpl.kt:190)
at kotlinx.coroutines.ChildContinuation.invoke(JobSupport.kt:1475)
at kotlinx.coroutines.JobSupport.notifyCancelling(JobSupport.kt:1500)
at kotlinx.coroutines.JobSupport.tryMakeCancelling(JobSupport.kt:795)
at kotlinx.coroutines.JobSupport.makeCancelling(JobSupport.kt:755)
at kotlinx.coroutines.JobSupport.cancelImpl$kotlinx_coroutines_core(JobSupport.kt:671)
at kotlinx.coroutines.JobSupport.parentCancelled(JobSupport.kt:637)
at kotlinx.coroutines.ChildHandleNode.invoke(JobSupport.kt:1466)
at kotlinx.coroutines.JobSupport.notifyCancelling(JobSupport.kt:1500)
at kotlinx.coroutines.JobSupport.tryMakeCompletingSlowPath(JobSupport.kt:900)
at kotlinx.coroutines.JobSupport.tryMakeCompleting(JobSupport.kt:863)
at kotlinx.coroutines.JobSupport.cancelMakeCompleting(JobSupport.kt:696)
at kotlinx.coroutines.JobSupport.cancelImpl$kotlinx_coroutines_core(JobSupport.kt:667)
at kotlinx.coroutines.JobSupport.cancelInternal(JobSupport.kt:632)
at kotlinx.coroutines.JobSupport.cancel(JobSupport.kt:617)
at kotlinx.coroutines.Job$DefaultImpls.cancel$default(Job.kt:183)
at androidx.compose.runtime.Recomposer.cancel(Recomposer.kt:781)
at androidx.compose.ui.test.AndroidComposeUiTestEnvironment.withWindowRecomposer(ComposeUiTest.android.kt:324)
at androidx.compose.ui.test.AndroidComposeUiTestEnvironment.access$withWindowRecomposer(ComposeUiTest.android.kt:217)
at androidx.compose.ui.test.AndroidComposeUiTestEnvironment$runTest$1$1$1$1.invoke(ComposeUiTest.android.kt:291)
at androidx.compose.ui.test.AndroidComposeUiTestEnvironment.withTestCoroutines(ComposeUiTest.android.kt:334)
at androidx.compose.ui.test.AndroidComposeUiTestEnvironment.access$withTestCoroutines(ComposeUiTest.android.kt:217)
at androidx.compose.ui.test.AndroidComposeUiTestEnvironment$runTest$1$1$1.invoke(ComposeUiTest.android.kt:290)
at androidx.compose.ui.test.junit4.EspressoLink.withStrategy(EspressoLink.android.kt:66)
at androidx.compose.ui.test.AndroidComposeUiTestEnvironment$runTest$1$1.invoke(ComposeUiTest.android.kt:289)
at androidx.compose.ui.test.junit4.IdlingResourceRegistry.withRegistry(IdlingResourceRegistry.jvm.kt:157)
at androidx.compose.ui.test.AndroidComposeUiTestEnvironment$runTest$1.invoke(ComposeUiTest.android.kt:288)
at androidx.compose.ui.test.junit4.ComposeRootRegistry.withRegistry(ComposeRootRegistry.android.kt:146)
at androidx.compose.ui.test.AndroidComposeUiTestEnvironment.runTest(ComposeUiTest.android.kt:287)
at androidx.compose.ui.test.junit4.AndroidComposeTestRule$apply$1.evaluate(AndroidComposeTestRule.android.kt:147)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at androidx.test.ext.junit.runners.AndroidJUnit4.run(AndroidJUnit4.java:162)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at androidx.test.internal.runner.TestExecutor.execute(TestExecutor.java:56)
at androidx.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:444)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2205)
ComposeView:
<androidx.compose.ui.platform.ComposeView
android:id="@+id/map_compose_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/black_50"
android:paddingHorizontal="14dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/venue_section" />
component:
@Composable
fun MiniMap(
latLng: LatLng,
modifier: Modifier = Modifier,
cornerRadius: Int = 10,
isMapUIControlsEnabled: Boolean = false,
onMapViewClicked: (() -> Unit)? = null
) {
val radius = LocalDensity.current.run { cornerRadius.dp.toPx() }
Box(
modifier = modifier
.clip(RoundedCornerShape(radius))
) {
val context = LocalContext.current
val cameraPositionState = rememberCameraPositionState {
position = CameraPosition.fromLatLngZoom(latLng, MAP_ZOOM_LEVEL)
}
val uiSettings by remember {
mutableStateOf(
MapUiSettings(
compassEnabled = false,
zoomControlsEnabled = isMapUIControlsEnabled,
zoomGesturesEnabled = isMapUIControlsEnabled,
tiltGesturesEnabled = isMapUIControlsEnabled,
indoorLevelPickerEnabled = isMapUIControlsEnabled,
mapToolbarEnabled = isMapUIControlsEnabled,
myLocationButtonEnabled = isMapUIControlsEnabled,
scrollGesturesEnabled = isMapUIControlsEnabled,
scrollGesturesEnabledDuringRotateOrZoom = isMapUIControlsEnabled,
)
)
}
GoogleMap(
modifier = Modifier.fillMaxSize(),
uiSettings = uiSettings,
cameraPositionState = cameraPositionState,
onMapClick = {
onMapViewClicked?.invoke()
},
properties = MapProperties(
mapStyleOptions = MapStyleOptions.loadRawResourceStyle(context, resourcesR.raw.google_map_style)
)
) {
Marker(
state = MarkerState(position = latLng),
onClick = {
onMapViewClicked?.invoke()
true
},
icon = ContextCompat.getDrawable(
context,
resourcesR.drawable.ic_dot_filled_36
)?.let {
bitMapFromVector(
vectorDrawable = it,
iconTint = ContextCompat.getColor(context, resourcesR.color.dice_yellow)
)
}
)
}
}
}
I've tried running the test on the UI thread but no luck it seems like an issue when disposing of the mapview. The implementation used from the activity also tried setting different disposition strategy.
@rakshitsoni02 could you test if it also happens with version 2.7.0?
Hi @rakshitsoni02 @polivmi1 , I am facing the same issue and it also happens with upgraded version, is there any fix/workaround for this issue?
hey @minaxiDH unfortunately no solid workaround I tried to dispose compose view in onstop() but still randomly failing the test suite
@minaxiDH @rakshitsoni02 Would you be able to provide a sample project with a test that causes this crash? Our project has instrumentation tests that don't have this issue, so there may be something different in your setup that we can investigate.
Reopening for comments from developers reporting this issue in the Maps SDK for Android issue tracker.
Experiencing the same issue when writing an automation test - crashing due to the following issue: com.google.maps.api.android.lib6.common.apiexception.c: Not on the main thread
Has anyone found any workarounds?
It doesn't throw if you change the rule from being createAndroidComposeRule<ComponentActivity>() to createAndroidComposeRule<MainActivity>().
Here's a project that reproduces the issue https://github.com/amrfarid140/googlemapscompose-issue-reporducer. It has 2 tests.
-
TestWithIssuethrows the error. It usescreateAndroidComposeRule<ComponentActivity>()then navigates toMainActivitywhere GoogleMap composable is created -
TestWithoutIssuedoesn't throw the error. It usescreateAndroidComposeRule<Main>()to launchMainActivitywhere GoogleMap composable is created.
To run the sample project you will need to replace Google Maps API key in the AndroidManifest. The key in there is not valid anymore.
Not sure if anyone is looking into this yet but something interesting I found was when the test fails.
The call to disposingComposition changes threads at the point of calling composition.dispose(). See screenshots.
| Phase | Screenshot |
|---|---|
calling factory() |
![]() |
calling awaitCancellation |
![]() |
| Disposing composition | ![]() |
When we launch a Google Map containing activity, the cancellation signal comes from a LifecycleObserver inside WrappedComposition which runs on the main thread.
When we launch an activity then navigate to a GoogleMap containing activity , the cancellation signal comes from AndroidComposeUiTestEnvironment which runs on the test thread.
Still don't know why this is happening.
I'm facing the same issue as well. Any update on this issue?
The workaround I have so far is to finish the activity/activities as part of the test instead of waiting for the test to tear down.
I'm using ActivityScenario to launch activities in test. I have this same issue when the Google Map containing activity is launched from another one.
Closing the activity with Espresso.pressBackUnconditionally() works for me.
@amrfarid140 @Ayskin thank you so much. Finally, it works.
This doesn't work if we need to assert on map screen, has anyone found any workaround on it?
@minaxiDH Any workaround for this issue?
@shriharsha-bhagwat this is still an open issue, we can't assert anything on map screen with composeView as it crashes with same exception, but it can be successfully closed using Espresso.pressBackUnconditionally()
Please comment here if you're still seeing this issue with v3.1.0.
started experiencing this issue with the same stacktrace as above with one of the instrumentation test that launches an Activity after updating the androidx.navigation library from 2.7.4 to the latest 2.7.5, is there a known conflict between the latest version of maps-compose and androidx.navigation?
Facing the same issue. Using last version.
Fix: Injecting the main dispatcher fixes the crash.
@get:Rule val composeTestRule = createComposeRule(
effectContext = EmptyCoroutineContext + Dispatchers.Main.immediate
)
(EmptyCoroutineContext is not necessary)
We're still seeing this on version 4.3.3 of the lib. Closing the app using pressBackUnconditionally() doesn't work reliably enough, and overriding the effectContext fails for other reasons.


