Zlatko
Zlatko

Reputation: 1487

Navigating with Compose not working with Google Maps on Android

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?

Upvotes: 3

Views: 1288

Answers (2)

DogeAmazed
DogeAmazed

Reputation: 888

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")
   }
}

Upvotes: 3

Zlatko
Zlatko

Reputation: 1487

After some debugging, I come to the conclusion that the problem is somehow related to Lifecycle.Event.ON_STOP -> mapView.onStop() getMapLifecycleObserver

Removing it solves the problem.

I'm not happy with the solution and would be happy if someone is able to provide a better solution, or at least an answer explaining more details about the problem.

Upvotes: 1

Related Questions