You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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的命名策略或自定义适配器)。

这就导致:

  1. Gson看不到Location类里私有的mLatitude/mLongitude字段;
  2. 它也不会把getLatitude()自动映射为你期望的lat字段(默认会映射为latitude);
  3. 最终生成的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 13:52:38