
lateinit 变量必须在首次访问前完成初始化,而本例中 drawRouteOnMap() 在网络响应返回前就被调用,导致访问未初始化的 polyline,触发 UninitializedPropertyAccessException。
lateinit 变量必须在首次访问前完成初始化,而本例中 `drawrouteonmap()` 在网络响应返回前就被调用,导致访问未初始化的 `polyline`,触发 `uninitializedpropertyaccessexception`。
在 Kotlin Android 开发中,lateinit 是一种常见的延迟初始化机制,适用于无法在声明时赋值、但能确保在使用前完成初始化的非空引用类型变量(如 String、自定义对象等)。然而,它不提供运行时安全防护——一旦在初始化前被读取,便会立即抛出 UninitializedPropertyAccessException,且该异常不可捕获(属于 RuntimeException 子类),直接导致应用崩溃。
问题根源在于执行时序错配:
-
routesDetails()发起异步网络请求(enqueue),其回调onResponse在主线程后续某个时刻执行; - 但
onMapReady()会在地图就绪后立即调用drawRouteOnMap(),此时polyline尚未被赋值(网络请求远未完成); - 因此
PolyUtil.decode(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.toString()
// ✅ 唯一安全调用点:赋值完成后立即绘制
drawRouteOnMap()
} else {
// ⚠️ 处理无路线/响应失败情况(如 Toast 提示、占位图)
Toast.makeText(this@CustomerMapActivity, "No route found", Toast.LENGTH_SHORT).show()
}
}
override fun onFailure(call: Call<RoutesResponse>, t: Throwable) {
Log.e("RouteAPI", "Request failed", t)
Toast.makeText(this@CustomerMapActivity, "Network error", Toast.LENGTH_SHORT).show()
}
})
}⚠️ 关键注意事项:
-
禁止在
onMapReady()中直接调用drawRouteOnMap()—— 此时polyline必然未初始化; -
避免在
lateinit变量上使用?.安全调用 ——lateinit不支持可空操作符,编译会报错; -
推荐替代方案(更健壮):若逻辑复杂或需多次访问,改用可空类型
var polyline: String? = null,配合?.let { }或requireNotNull()显式校验:private var polyline: String? = null // ... 赋值同上 private fun drawRouteOnMap() { polyline?.let { points -> val decoded = PolyUtil.decode(points) // 绘制逻辑 } ?: run { Log.w("Map", "Polyline not available yet") } } -
调试技巧:利用
::polyline.isInitialized检查状态(仅限lateinit),便于日志追踪:Log.d("Debug", "polyline initialized: ${::polyline.isInitialized}")
总结:lateinit 是一把双刃剑——它简化了非空约束,但也要求开发者严格把控初始化时机。异步场景下,所有对 lateinit 的访问必须收敛到其初始化完成的回调内部,这是避免崩溃的黄金法则。

















