I have a composable containing a google maps view. When I click on a pin on the map I would like to trigger navController.navigate
so I can navigate to another composable. However, when I call it the application gets stuck instead of navigating. Navigating on a button clicks works as expected.
I have also created a very simple application that is demonstrating the problem. The MainActivity
looks like this:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val navController = rememberNavController()
NavHost(navController = navController, startDestination = "Screen1") {
composable("Screen1") {
Button({ navController.navigate("MapsScreen") }) {
Text(text = "Go to Maps")
}
}
composable("MapsScreen") {
val mapView = rememberMapViewWithLifecycle()
AndroidView({ mapView }) { mapView ->
mapView.getMapAsync { map ->
map.setOnInfoWindowClickListener {
navController.navigate("Screen1")
}
val markerOptions = MarkerOptions()
.position(LatLng(41.390205, 2.154007))
.title("Barcelona")
map.addMarker(markerOptions)!!
}
}
}
}
}
}
}
@Composable
fun rememberMapViewWithLifecycle(): MapView {
val context = LocalContext.current
val mapView = remember {
MapView(context).apply {
id = R.id.map
}
}
val lifecycle = LocalLifecycleOwner.current.lifecycle
DisposableEffect(lifecycle, mapView) {
// Make MapView follow the current lifecycle
val lifecycleObserver = getMapLifecycleObserver(mapView)
lifecycle.addObserver(lifecycleObserver)
onDispose {
lifecycle.removeObserver(lifecycleObserver)
}
}
return mapView
}
private fun getMapLifecycleObserver(mapView: MapView): LifecycleEventObserver =
LifecycleEventObserver { _, event ->
when (event) {
Lifecycle.Event.ON_CREATE -> mapView.onCreate(Bundle())
Lifecycle.Event.ON_START -> mapView.onStart()
Lifecycle.Event.ON_RESUME -> mapView.onResume()
Lifecycle.Event.ON_PAUSE -> mapView.onPause()
Lifecycle.Event.ON_STOP -> mapView.onStop()
Lifecycle.Event.ON_DESTROY -> mapView.onDestroy()
else -> throw IllegalStateException()
}
}
In the project I use androidx.navigation:navigation-compose:2.4.0-beta02
which is the latest version at the moment according to the documentation.
The complete project is available on Github
As an inspiration for the example I have used: Using Google Maps in a Jetpack Compose app and Crane Sample
What could be the problem and how to solve it?
It seems like when you navigate inside the setOnInfoWindowClickListener
method, you'll cause an deadlock.
Try to asynchronously navigate to your target to circumvent the deadlock, e.g. by using GlobalScope.launch
on Dispatchers.Main
, so the listener can run to the end without any deadlock:
map.setOnInfoWindowClickListener {
GlobalScope.launch(Dispatchers.Main) {
navController.navigate("Screen1")
}
}