Android中Gson转换Location模型丢失经纬度字段的原因排查
为什么Gson序列化Android Location类时lat/lng字段丢失?
这个问题其实挺典型的,我之前处理类似场景时也踩过坑,核心原因是Gson的默认序列化逻辑和Android Location类的内部实现不兼容,具体拆解如下:
问题根源
Android的Location类并没有暴露名为lat或lng的public字段——你在Kotlin代码里写的location.lat/location.lng,其实是Kotlin根据JavaBean规范自动生成的属性代理,底层对应Location类的getLatitude()/setLatitude()、getLongitude()/setLongitude()方法,而Location类中存储经纬度的实际字段(比如mLatitude、mLongitude)是私有的。
Gson默认采用**基于字段(Field-Based)**的序列化策略:
- 只会扫描类的public实例字段进行序列化/反序列化;
- 不会自动将JavaBean风格的getter/setter方法映射为JSON字段(除非你显式配置Gson的命名策略或自定义适配器)。
这就导致:
- Gson看不到
Location类里私有的mLatitude/mLongitude字段; - 它也不会把
getLatitude()自动映射为你期望的lat字段(默认会映射为latitude); - 最终生成的JSON字符串里根本没有
lat/lng键,反序列化时自然无法给newLocation的经纬度赋值,只能用默认的0.0。
解决方案
如果你不想用自定义类,有两种方式可以解决这个问题:
1. 配置Gson识别JavaBean getter/setter
通过GsonBuilder配置命名策略,让Gson将getLatitude()映射为lat,getLongitude()映射为lng:
val gson = GsonBuilder() .setFieldNamingStrategy { field -> // 自定义命名映射:将getLatitude()对应的字段名转为lat when (field.name) { "latitude" -> "lat" "longitude" -> "lng" else -> field.name } } .create()
这样序列化后的JSON会包含lat和lng字段,反序列化时也能正确赋值。
2. 自定义TypeAdapter(推荐)
直接为Location类写一个专属的TypeAdapter,完全控制序列化/反序列化逻辑:
class LocationTypeAdapter : TypeAdapter<Location>() { override fun write(out: JsonWriter, location: Location) { out.beginObject() out.name("lat").value(location.latitude) out.name("lng").value(location.longitude) // 如果需要序列化Location的其他字段,比如精度、提供者等,在这里添加 out.name("accuracy").value(location.accuracy) out.name("provider").value(location.provider) out.endObject() } override fun read(`in`: JsonReader): Location { val location = Location("") // 传入空字符串作为默认提供者 `in`.beginObject() while (`in`.hasNext()) { when (`in`.nextName()) { "lat" -> location.latitude = `in`.nextDouble() "lng" -> location.longitude = `in`.nextDouble() "accuracy" -> location.accuracy = `in`.nextFloat() "provider" -> location.provider = `in`.nextString() else -> `in`.skipValue() // 忽略未知字段 } } `in`.endObject() return location } } // 使用时注册适配器 val gson = GsonBuilder() .registerTypeAdapter(Location::class.java, LocationTypeAdapter()) .create()
补充:为什么Location类无法直接正常工作?
简单来说就是设计理念不匹配:
- Android的
Location类是为Android框架内部使用设计的,它通过getter/setter暴露数据,而非直接公开字段; - Gson默认的序列化逻辑更偏向于处理POJO(普通Java对象),即那些拥有public字段的简单类,对于封装性强的框架类,就需要额外配置才能适配。
内容的提问来源于stack exchange,提问作者FarshidABZ
相关产品推荐
相关产品推荐

