My MapsActivity无错误提示崩溃,协程调用Room数据触发主线程异常
问题原因
- 直接触发崩溃的原因:你通过
by viewModels()懒加载声明ViewModel,首次访问mapsViewModel是在getRoutePoints()方法内部的Dispatchers.IO协程中,属于子线程。而ViewModel初始化过程中需要调用addObserver绑定生命周期,该方法强制要求在主线程执行,因此抛出IllegalStateException异常。 - 代码还存在隐性逻辑错误:
getRoutePoints()方法内部启动异步协程给points赋值后直接返回,此时IO协程还未执行完成,你永远无法拿到数据库返回的真实点位数据,只会得到空列表。
修复方案
- 改造
getRoutePoints()方法:移除内部自建的协程,将方法改为挂起函数直接返回ViewModel的查询结果。Room的挂起函数默认会自动调度到IO线程执行,不需要手动切换线程。
// Gets the points from room repository through ViewModel private suspend fun getRoutePoints(): List<PointOfInterest> { val route = getRouteId() return mapsViewModel.getRoutePoints(route) }
- 替换协程作用域:把
onMapReady里自定义的CoroutineScope替换为Android官方提供的lifecycleScope,它会和Activity生命周期绑定,页面销毁时自动取消协程避免内存泄漏,且默认运行在主线程。
override fun onMapReady(googleMap: GoogleMap) { mMap = googleMap lifecycleScope.launch { val listOfPoints = getRoutePoints() for (point in listOfPoints) { mMap.addMarker(MarkerOptions().position(LatLng( point.latitude, point.longitude))) // 替换listOfPoints[0]避免空列表下标越界 if (point == listOfPoints.firstOrNull()) { mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(LatLng(point.latitude, point.longitude), 18f)) } } } }
补充:如果项目未引入lifecycle相关ktx依赖,需要在模块级build.gradle中添加依赖:
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.6.2"
- 可选优化:如果担心ViewModel懒加载触发时机问题,可以在
onCreate方法中提前访问一次mapsViewModel,确保在主线程完成初始化。
内容的提问来源于stack exchange,提问作者albertbuigues
相关产品推荐
相关产品推荐

