Jetpack Compose MapView with custom map tile overlay

399 Views Asked by At

I'm trying to use AndroidView to create a MapView with custom map tile overlay:

AndroidView(
modifier = Modifier.fillMaxSize(),
    factory = {
        mapView
    },
    update = {mapView->
        mapView.getMapAsync {googleMap ->
            googleMap.mapType = GoogleMap.MAP_TYPE_NONE
            googleMap.addTileOverlay(TileOverlayOptions().tileProvider(object :
                    UrlTileProvider(256, 256) {
                private val baseUrl = resources.getString(R.string.custom_tile_url)
                override fun getTileUrl(x: Int, y: Int, zoom: Int): URL? {
                    return URL(
                            baseUrl.replace("{z}", zoom.toString())
                                    .replace("{x}", x.toString())
                                    .replace("{y}", y.toString())
                    )
                }
            }))
        }
    }
)

mapView is initialized with rememberMapViewWithLifecycle referenced from another article.

However, I see the blank mapView : seems that GoogleMap.MAP_TYPE_NONE is in effect.

  1. If I comment out everything inside getMapAsync then I get the default Google Map, so I'm pretty sure that I've got all the manifest and map initialization correct.
  2. I have traced my code an sure that the formatted URL links to valid map tile. And the getTileUrl function did get called.

I'm wondering if there's something I've missed?

Thanks.

1

There are 1 best solutions below

0
Howard Wu On

OK, seems that I shouldn't put those in update stage. After moved those calls to the Lifecycle.Event.ON_CREATE, the map showing well.

@Composable
fun myMapView() {
    val mapView = rememberMapViewWithLifecycle()
    AndroidView(
        modifier = Modifier.fillMaxSize(), // Occupy the max size in the Compose UI tree
        factory = {
            mapView
        },
    )
}

@Composable
fun rememberMapLifecycleObserver(mapView: MapView): LifecycleEventObserver =
    remember(mapView) {
        LifecycleEventObserver { _, event ->
            when (event) {
                Lifecycle.Event.ON_CREATE -> {
                    mapView.onCreate(Bundle())
                    mapView.getMapAsync {googleMap ->
                        googleMap.mapType = GoogleMap.MAP_TYPE_NONE
                        googleMap.addTileOverlay(TileOverlayOptions().tileProvider(object :
                                UrlTileProvider(256, 256) {
                            private val baseUrl = resources.getString(R.string.custom_tile_url)
                            override fun getTileUrl(x: Int, y: Int, zoom: Int): URL? {
                                return URL(
                                        baseUrl.replace("{z}", zoom.toString())
                                                .replace("{x}", x.toString())
                                                .replace("{y}", y.toString())
                                )
                            }
                        }))
                    }
                }
                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()
            }
        }
    }