如何在 Jetpack Compose 中处理 Mapbox Map 的 activity 生命周期事件?

How to handle activity lifecycle events for Mapbox Map in Jetpack Compose?

在 android 的 Mapbox SDK 官方文档中,有一个使用标准 UI 库 Android 的简单地图示例。可以找到有关问题完整性的完整文档 here

那里提到的代码是这样的:

private var mapView: MapView? = null
 
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
 
Mapbox.getInstance(this, getString(R.string.mapbox_access_token))
 
setContentView(R.layout.activity_main)
 
mapView = findViewById(R.id.mapView)
mapView?.onCreate(savedInstanceState)
mapView?.getMapAsync { mapboxMap ->
 
    mapboxMap.setStyle(Style.MAPBOX_STREETS) {
 
        // Map is set up and the style has loaded. Now you can add data or make other map adjustments
    }
 
   }
}

处理activity和mapbox地图生命周期事件的代码如下:

override fun onStart() {
    super.onStart()
    mapView?.onStart()
}
 
override fun onResume() {
    super.onResume()
    mapView?.onResume()
}
 
override fun onPause() {
    super.onPause()
    mapView?.onPause()
}
 
override fun onStop() {
    super.onStop()
    mapView?.onStop()
}
 
override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState)
    mapView?.onSaveInstanceState(outState)
}
 
override fun onLowMemory() {
    super.onLowMemory()
    mapView?.onLowMemory()
}
 
override fun onDestroy() {
    super.onDestroy()
    mapView?.onDestroy()
}

我的问题是,如果在 jetpack compose 中使用 mapbox 地图,地图的那些事件是自动处理的,还是需要开发人员自己处理? 我在问,因为我不想对如何处理关于 Jetpack 中的 AndroidView 的最佳实践有任何疑问,特别是当地图放置在任何特定 activity 或片段之外的可组合时.

Jetpack compose 代码片段的完整性:

@Composable
fun MapWithFab() {

    ConstraintLayout(modifier = Modifier.fillMaxSize()) {
        val mapboxMap = createRef()
        val fab = createRef()

        AndroidView(
            modifier = Modifier
                .fillMaxSize()
                .padding(bottom = 35.dp)
                .constrainAs(mapboxMap) {
                    top.linkTo(parent.top)
                    start.linkTo(parent.start)
                    end.linkTo(parent.end)
                    bottom.linkTo(parent.bottom)
                },
            factory = { context ->
                Mapbox.getInstance(
                    context,
                    context.getString(R.string.mapbox_access_token)
                )
                MapView(context).apply {
                    getMapAsync { mapboxMap ->
                        mapboxMap.setStyle(Style.MAPBOX_STREETS)

                        val position = CameraPosition.Builder()
                            .target(LatLng(51.04004014308637, 13.744085852141072))
                            .zoom(15.0)
                            .build()

                        mapboxMap.animateCamera(CameraUpdateFactory.newCameraPosition(position), 1)
                    }
                }
            }
        )

        FloatingActionButton(
            onClick = { },
            modifier = Modifier
                .padding(25.dp)
                .width(50.dp)
                .height(50.dp)
                .constrainAs(fab) {
                    end.linkTo(mapboxMap.end)
                    bottom.linkTo(mapboxMap.bottom)
                }
        ) {

        }
    }
}

感谢您的回答和想法。

原来在 google 上的 compose 示例项目之一中提到了,github 上的代码和项目可以找到 here

可以这样做:

@Composable
fun MapWrapper() {
    ConstraintLayout(modifier = Modifier.fillMaxSize()) {
        val mapboxMap = createRef()
        val fab = createRef()
        val mapView = rememberMapViewWithLifecycle()


        AndroidView(
            factory = {mapView},
            modifier = Modifier.constrainAs(mapboxMap) {
                top.linkTo(parent.top)
                bottom.linkTo(parent.bottom)
                start.linkTo(parent.start)
                end.linkTo(parent.end)
        })

        FloatingActionButton(
            onClick = {

            },
            modifier = Modifier
                .padding(25.dp)
                .width(50.dp)
                .height(50.dp)
                .constrainAs(fab) {
                    end.linkTo(mapboxMap.end)
                    bottom.linkTo(mapboxMap.bottom)
                }
        ) {

        }
    }
}

@Composable
fun rememberMapViewWithLifecycle(): MapView {
    val context = LocalContext.current
    val mapView = remember {
        Mapbox.getInstance(
            context,
            context.getString(R.string.mapbox_access_token)
        )
        MapView(context).apply {
            val mapView = this
            getMapAsync { mapboxMap ->
                mapboxMap.setStyle(Style.MAPBOX_STREETS)

                val position = CameraPosition.Builder()
                    .target(LatLng(70.04004014308637, -20.744085852141072))
                    .zoom(15.0)
                    .build()

                mapboxMap.animateCamera(CameraUpdateFactory.newCameraPosition(position), 1)

                mapboxMap.getStyle {
                }
            }
        }
    }

    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
}

/**
 * Handles lifecycle of provided 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()
        }
    }

几乎所有需要响应生命周期事件的 AndroidView 都可以通过这种方式实现。这个实现唯一缺少的是没有处理 onLowMemory() 案例。

更新 - 注意:上面的解决方案是解决 MapboxMaps v9 的生命周期,MapboxMaps v10 已经集成了它。