
lateinit 变量在赋值前被访问会抛出 UninitializedPropertyAccessException;本例中 polyline 在异步网络请求完成前,就被 drawRouteOnMap() 提前读取,导致崩溃。
```lateinit``` 变量在赋值前被访问会抛出 `uninitializedpropertyaccessexception`;本例中 `polyline` 在异步网络请求完成前,就被 `drawrouteonmap()` 提前读取,导致崩溃。
问题根源:异步执行时序错位
在你的代码中,routesDetails() 发起的是一个异步网络请求(requestCall.enqueue(...)),而 onMapReady() 是由 Google Maps SDK 在地图就绪后立即回调的——它不等待网络请求完成。因此,drawRouteOnMap() 很可能在 polyline = ... 这行赋值语句执行之前就被调用,触发 UninitializedPropertyAccessException。
关键时间线如下:
-
onCreate()→ 调用routesDetails()(发起异步请求) -
onMapReady()→ 几乎同时触发 → 调用drawRouteOnMap() -
drawRouteOnMap()尝试读取polyline→ ❌ 未初始化 → 崩溃 - 网络响应返回 →
polyline才被赋值(但已太晚)
✅ 正确做法:确保依赖逻辑在数据就绪后执行
不要让 drawRouteOnMap() 无条件执行,而应仅在网络响应成功、polyline 已赋值后才绘制路线。推荐两种稳健方案:
方案一:在回调中绘制(推荐 · 简洁直接)
将绘图逻辑移入网络响应成功分支,避免竞态:
private fun routesDetails(origin: String, destination: String, apiKey: String) {
val routeService = ServiceBuilder.buildService(RouteService::class.java)
val requestCall = routeService.getRoutes(origin, destination, apiKey)
requestCall.enqueue(object : Callback<routesresponse> {
override fun onResponse(
call: Call<routesresponse>,
response: Response<routesresponse>
) {
if (response.isSuccessful && response.body()?.routes?.isNotEmpty() == true) {
polyline = response.body()!!.routes[0].overview_polyline.points
// ✅ 数据就绪后,再绘制路线(需确保地图已就绪)
mMap?.let { map ->
drawRouteOnMap(map) // 传入 map 实例,避免 onMapReady 未触发的隐患
} ?: run {
// 地图尚未就绪?可缓存 polyline,待 onMapReady 后再绘
pendingPolyline = polyline
}
}
}
override fun onFailure(call: Call<routesresponse>, t: Throwable) {
Log.e("Route", "Failed to fetch route", t)
}
})
}</routesresponse></routesresponse></routesresponse></routesresponse>
同时修改 drawRouteOnMap 为接收 GoogleMap 参数,并在 onMapReady 中检查缓存:
private var pendingPolyline: String? = null
override fun onMapReady(mMap: GoogleMap) {
this.mMap = mMap // 保存引用(建议声明为 lateinit var mMap: GoogleMap)
// 若已有 polyline,立即绘制;否则等待网络回调
pendingPolyline?.let {
drawRouteOnMap(mMap)
pendingPolyline = null
}
}
private fun drawRouteOnMap(map: GoogleMap) {
val decodedPolyline = PolyUtil.decode(polyline)
map.addPolyline(PolylineOptions()
.addAll(decodedPolyline)
.width(10f)
.color(ContextCompat.getColor(this, R.color.route_color))
)
}
方案二:使用 isInitialized 安全检查(辅助防御)
虽不能替代时序控制,但可增强健壮性:
private fun drawRouteOnMap() {
if (::polyline.isInitialized) {
val decodedPolyline = PolyUtil.decode(polyline)
mMap?.addPolyline(PolylineOptions().addAll(decodedPolyline).width(10f))
} else {
Log.w("Map", "polyline not ready yet — skipping draw")
// 可选:重试机制或 Toast 提示
}
}
⚠️ 注意事项:
::polyline.isInitialized仅适用于lateinit,不可用于普通var或val;- 不要依赖
try-catch包裹lateinit访问——这掩盖了设计缺陷,而非解决问题;- 始终确保
mMap非空(如使用?.let或!!前校验),避免 NPE;- 生产环境建议配合加载状态(如
ProgressBar)提升用户体验。
总结
UninitializedPropertyAccessException 的本质是同步逻辑误用在异步场景中。解决核心在于:将依赖 lateinit 变量的操作,严格绑定到其初始化完成的时机之后——无论是通过回调驱动、状态缓存,还是协程 await(),目标都是建立明确的数据就绪信号。避免“先用后赋值”的隐式假设,才能写出稳定可靠的 Kotlin Android 代码。










