Android Jetpack compose:使用谷歌地图在地图创建时崩溃

Posted

技术标签:

【中文标题】Android Jetpack compose:使用谷歌地图在地图创建时崩溃【英文标题】:Android Jetpack compose: Using google map got crash on map create 【发布时间】:2021-02-17 18:46:35 【问题描述】:

我试图在 google compose 示例项目调用 Crane 的帮助下实现 google map: https://github.com/android/compose-samples/tree/main/Crane

我使用相同的实现并使用 MapViewUtils 来实现 map 的 lifeCycler 并防止重新组合内容等等...我把所有的 android 地图键和权限在清单上, 但是我的代码在地图开始时崩溃了:

这就是我想展示地图的地方:

@Composable
fun MapScreen(latitude: String, longitude: String) 
    // The MapView lifecycle is handled by this composable. As the MapView also needs to be updated
    // with input from Compose UI, those updates are encapsulated into the MapViewContainer
    // composable. In this way, when an update to the MapView happens, this composable won't
    // recompose and the MapView won't need to be recreated.
    val mapView = rememberMapViewWithLifecycle()
    MapViewContainer(mapView, latitude, longitude)


@Composable
private fun MapViewContainer(
    map: MapView,
    latitude: String,
    longitude: String
) 
//    var zoom by savedInstanceState  InitialZoom 

    AndroidView( map )  mapView ->
        // Reading zoom so that AndroidView recomposes when it changes. The getMapAsync lambda
        mapView.getMapAsync 
            val position = LatLng(latitude.toDouble(), longitude.toDouble())
            it.addMarker(
                MarkerOptions().position(position)
            )
            it.moveCamera(CameraUpdateFactory.newLatLng(position))
        
    

这是在 Util 类中:

@Composable
fun rememberMapViewWithLifecycle(): MapView 
    val context = ContextAmbient.current
    val mapView = remember 
        MapView(context).apply 
            id = R.id.map
        
    

//     Makes MapView follow the lifecycle of this composable
    val lifecycleObserver = rememberMapLifecycleObserver(mapView)
    val lifecycle = LifecycleOwnerAmbient.current.lifecycle
    onCommit(lifecycle) 
        lifecycle.addObserver(lifecycleObserver)
        onDispose 
            lifecycle.removeObserver(lifecycleObserver)
        
    

    return mapView


@Composable
private fun rememberMapLifecycleObserver(mapView: MapView): LifecycleEventObserver =
    remember(mapView) 
        LifecycleEventObserver  _, event ->
            when (event) 
                Lifecycle.Event.ON_CREATE -> mapView.onCreate(Bundle()) //Crashes here
                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()
            
        
    

我遇到了这个崩溃:

2020-11-05 12:16:09.282 2665-3383/com.google.android.gms.persistent E/ModuleIdSetter: exception when setting module id
    java.lang.IllegalStateException: Unable to get current module info in ModuleManager created with non-module Context
        at com.google.android.chimera.config.ModuleManager.getCurrentModule(:com.google.android.gms@202414022@20.24.14 (040700-319035315):2)
        at aewd.a(:com.google.android.gms@202414022@20.24.14 (040700-319035315):4)
        at aewg.b(:com.google.android.gms@202414022@20.24.14 (040700-319035315):9)
        at aeso.a(Unknown Source:0)
        at rpm.a(:com.google.android.gms@202414022@20.24.14 (040700-319035315):0)
        at rlv.c(:com.google.android.gms@202414022@20.24.14 (040700-319035315):1)
        at rlt.b(:com.google.android.gms@202414022@20.24.14 (040700-319035315):1)
        at rok.b(:com.google.android.gms@202414022@20.24.14 (040700-319035315):6)
        at rok.c(:com.google.android.gms@202414022@20.24.14 (040700-319035315):6)
        at rok.b(:com.google.android.gms@202414022@20.24.14 (040700-319035315):10)
        at rok.a(:com.google.android.gms@202414022@20.24.14 (040700-319035315):17)
        at rok.g(:com.google.android.gms@202414022@20.24.14 (040700-319035315):3)
        at sdr.a(:com.google.android.gms@202414022@20.24.14 (040700-319035315):2)
        at scr.a(:com.google.android.gms@202414022@20.24.14 (040700-319035315):10)
        at sci.a(:com.google.android.gms@202414022@20.24.14 (040700-319035315):0)
        at scl.handleMessage(:com.google.android.gms@202414022@20.24.14 (040700-319035315):28)
        at android.os.Handler.dispatchMessage(Handler.java:107)
        at aekz.a(:com.google.android.gms@202414022@20.24.14 (040700-319035315):2)
        at aekz.dispatchMessage(:com.google.android.gms@202414022@20.24.14 (040700-319035315):14)
        at android.os.Looper.loop(Looper.java:214)
        at android.os.HandlerThread.run(HandlerThread.java:67)

【问题讨论】:

【参考方案1】:

您需要获得访问用户位置的权限,并在显示地图之前确保您拥有该权限。您可以使用带有 LiveDataViewModel 的变量,该变量在授予权限时更新,这是示例的一部分:

class MainViewModel : ViewModel() 
    private val _permissionGranted = MutableLiveData(false)
    val permissionGranted = _permissionGranted
    
    fun onPermissionGranted() = _permissionGranted.postValue(true)
    
    // ...

class MainActivity : AppCompatActivity() 
    private val mainViewModel by viewModels<MainViewModel>
    
    override fun onCreate(savedInstanceState: Bundle?) 
        super.onCreate(savedInstanceState)
        setContent 
            val permissionGranted = mainViewModel.permissionGranted.observeAsState()
            if (permissionGranted) 
                // logic to show your map
             else 
                // logic to ask for permission
            
        
    
    
    override fun onRequestPermissionsResult(requestCode: Int,
        permissions: Array<String>, grantResults: IntArray) 
        // check if it's your request
        mainViewModel.onPremissionGranted()
    
    
    // ...

您可以在此处获取有关请求权限的更多信息:https://developer.android.com/training/permissions/requesting

【讨论】:

正如我提到的,我处理了所有权限。崩溃与权限无关。 您很难过在清单中添加了权限,但您请求了权限吗? 位置不是危险权限,需要单独询问。放入清单就足够了。 你必须请求位置许可,根据文档:developer.android.com/training/location/permissions 好吧,我没有问,它起作用了,因为我没有从用户那里得到任何位置,只是想在地图上显示一些东西。我想这就是原因。顺便说一句,我现在可以在我的应用程序上使用旧方式地图,而无需应用程序内的许可,而且效果很好。嗯,这可能与我使用 com.google.android.gsm.map 的旧方式有关,但在那个例子中他们使用 lcom.google.android.libraries.maps?所以在第二个总是必须在应用程序许可?!【参考方案2】:

去掉从“fun rememberMapViewWithLifecycle(): MapView”到“fun rememberMapViewWithLifecycle()”的返回类型

很明显,您的可组合函数正在返回一个 MapView,但它不应该返回一个类型才能被视为可组合函数。 我引用“https://developer.android.com/jetpack/compose/mental-model"

""" 该函数不返回任何内容。发出 UI 的 Compose 函数不需要返回任何内容,因为它们描述了所需的屏幕状态,而不是构造 UI 小部件。

"""

【讨论】:

以上是关于Android Jetpack compose:使用谷歌地图在地图创建时崩溃的主要内容,如果未能解决你的问题,请参考以下文章

Android Jetpack Compose学习—— Jetpack compose基础布局

Android Jetpack Compose学习—— Jetpack compose基础布局

Android Jetpack Compose学习—— Jetpack compose入门

Android Jetpack Compose学习—— Jetpack compose入门

如何使用 Jetpack Compose 使 LinearProgressIndicator 宽度动态化

Android Kotlin Jetpack Compose 使用