改造响应对象中的嵌入式房间实体字段未在运行时初始化
Embedded room entity field in retrofit response object not initialized at runtime
我有一个 CurrentWeatherResponse
对象,其中包含使用 Retrofit 从天气 API 恢复的 JSON 数据。这是 JSON 响应格式:
{
"latitude": 37.8267,
"longitude": -122.4233,
"timezone": "America/Los_Angeles",
"currently": {
"time": 1587054875,
"summary": "Mostly Cloudy",
"icon": "partly-cloudy-day",
"nearestStormDistance": 107,
"nearestStormBearing": 119,
"precipIntensity": 0,
"precipProbability": 0,
"temperature": 11.49,
"apparentTemperature": 11.49,
"dewPoint": 10.14,
"humidity": 0.91,
"pressure": 1012.9,
"windSpeed": 2.73,
"windGust": 3.84,
"windBearing": 171,
"cloudCover": 0.64,
"uvIndex": 2,
"visibility": 16.093,
"ozone": 360.9
},
"offset": -7
}
在 CurrentWeatherResponse
中,我分别有两个字段 currentWeatherEntry: CurrentWeatherEntry
和 val location: WeatherLocation
。这些字段中的每一个都是一个房间 @Entity
class。现在我注意到,尽管 "currently"
json 数据已成功传递到 CurrentWeatherEntry
字段,但 @Embedded
位置 WeatherLocation
字段从未初始化。当我 运行 应用程序或使用数据库检查器时,我可以看到 WeatherLocation
实体甚至没有初始化其 ID 字段。我在这里错过了什么?
当前天气响应class:
data class CurrentWeatherResponse(
// Tells GSON that the "currently" field of the JSON returned by the
// API should be tied with our CurrentWeatherEntry data class
@SerializedName("currently")
val currentWeatherEntry: CurrentWeatherEntry,
@Embedded
val location: WeatherLocation
) {
init {
location.setEpochTimeVal(currentWeatherEntry.time)
}
}
CurrentWeatherEntry 实体:
const val CURRENT_WEATHER_ID = 0
@Entity(tableName = "current_weather")
data class CurrentWeatherEntry(
val time: Long, // epoch timestamp
val icon: String,
val summary: String,
val precipProbability: Double,
val temperature: Double
) {
@PrimaryKey(autoGenerate = false)
var id:Int = CURRENT_WEATHER_ID
}
WeatherLocaiton 实体:
const val WEATHER_LOCATION_ID = 0
@Entity(tableName = "weather_location")
data class WeatherLocation(
val latitude: Double,
val longitude: Double,
val timezone: String
) {
@PrimaryKey(autoGenerate = false)
var id:Int = WEATHER_LOCATION_ID
private var epochTimeVal:Long = 0
val zonedDateTime:ZonedDateTime
get() {
val instant = Instant.ofEpochMilli(this.epochTimeVal)
val zoneId = ZoneId.of(timezone)
return ZonedDateTime.ofInstant(instant,zoneId)
}
fun setEpochTimeVal(time:Long) {
this.epochTimeVal = time}
fun getEpochTimeVal() : Long = epochTimeVal
}
如果我正确理解了你的问题,我不得不说 @Embedded
注释是 Room
的注释,而不是 Gson
的注释。因此,通过 Retrofit 将您的响应转换为 Kotlin 数据对象不会发挥作用。
@Embedded
注释仅对 Room Dao 可见 class 以将关系数据库转换为您方便的对象模型。
因此您需要为 Gson 编写自己的 TypeConvertor
。
如@MahdiRajabi 所述,@Embedded
注释由 Room 使用,而不是 Gson。这意味着从 JSON 响应返回到 CurrentWeatherResponse
class 的 latitude
、longitude
和 timezone
字段被简单地忽略并且location:WeatherLocation
字段被简单分配 null
。我通过在 CurrentWeatherResponse
中显式定义 latitude
、longitude
和 timezone
字段然后在 [=23= 时返回 WeatherLocation
的实例来解决我的问题] 字段使用 getter 访问。现在一切正常!
data class CurrentWeatherResponse(
// Tells GSON that the "currently" field of the JSON returned by the
// API should be tied with our CurrentWeatherEntry data class
@SerializedName("currently")
val currentWeatherEntry: CurrentWeatherEntry,
val latitude:Double,
val longitude:Double,
val timezone:String
) {
val location:WeatherLocation
get() = WeatherLocation(latitude,longitude,timezone,currentWeatherEntry.time)
}
我有一个 CurrentWeatherResponse
对象,其中包含使用 Retrofit 从天气 API 恢复的 JSON 数据。这是 JSON 响应格式:
{
"latitude": 37.8267,
"longitude": -122.4233,
"timezone": "America/Los_Angeles",
"currently": {
"time": 1587054875,
"summary": "Mostly Cloudy",
"icon": "partly-cloudy-day",
"nearestStormDistance": 107,
"nearestStormBearing": 119,
"precipIntensity": 0,
"precipProbability": 0,
"temperature": 11.49,
"apparentTemperature": 11.49,
"dewPoint": 10.14,
"humidity": 0.91,
"pressure": 1012.9,
"windSpeed": 2.73,
"windGust": 3.84,
"windBearing": 171,
"cloudCover": 0.64,
"uvIndex": 2,
"visibility": 16.093,
"ozone": 360.9
},
"offset": -7
}
在 CurrentWeatherResponse
中,我分别有两个字段 currentWeatherEntry: CurrentWeatherEntry
和 val location: WeatherLocation
。这些字段中的每一个都是一个房间 @Entity
class。现在我注意到,尽管 "currently"
json 数据已成功传递到 CurrentWeatherEntry
字段,但 @Embedded
位置 WeatherLocation
字段从未初始化。当我 运行 应用程序或使用数据库检查器时,我可以看到 WeatherLocation
实体甚至没有初始化其 ID 字段。我在这里错过了什么?
当前天气响应class:
data class CurrentWeatherResponse(
// Tells GSON that the "currently" field of the JSON returned by the
// API should be tied with our CurrentWeatherEntry data class
@SerializedName("currently")
val currentWeatherEntry: CurrentWeatherEntry,
@Embedded
val location: WeatherLocation
) {
init {
location.setEpochTimeVal(currentWeatherEntry.time)
}
}
CurrentWeatherEntry 实体:
const val CURRENT_WEATHER_ID = 0
@Entity(tableName = "current_weather")
data class CurrentWeatherEntry(
val time: Long, // epoch timestamp
val icon: String,
val summary: String,
val precipProbability: Double,
val temperature: Double
) {
@PrimaryKey(autoGenerate = false)
var id:Int = CURRENT_WEATHER_ID
}
WeatherLocaiton 实体:
const val WEATHER_LOCATION_ID = 0
@Entity(tableName = "weather_location")
data class WeatherLocation(
val latitude: Double,
val longitude: Double,
val timezone: String
) {
@PrimaryKey(autoGenerate = false)
var id:Int = WEATHER_LOCATION_ID
private var epochTimeVal:Long = 0
val zonedDateTime:ZonedDateTime
get() {
val instant = Instant.ofEpochMilli(this.epochTimeVal)
val zoneId = ZoneId.of(timezone)
return ZonedDateTime.ofInstant(instant,zoneId)
}
fun setEpochTimeVal(time:Long) {
this.epochTimeVal = time}
fun getEpochTimeVal() : Long = epochTimeVal
}
如果我正确理解了你的问题,我不得不说 @Embedded
注释是 Room
的注释,而不是 Gson
的注释。因此,通过 Retrofit 将您的响应转换为 Kotlin 数据对象不会发挥作用。
@Embedded
注释仅对 Room Dao 可见 class 以将关系数据库转换为您方便的对象模型。
因此您需要为 Gson 编写自己的 TypeConvertor
。
如@MahdiRajabi 所述,@Embedded
注释由 Room 使用,而不是 Gson。这意味着从 JSON 响应返回到 CurrentWeatherResponse
class 的 latitude
、longitude
和 timezone
字段被简单地忽略并且location:WeatherLocation
字段被简单分配 null
。我通过在 CurrentWeatherResponse
中显式定义 latitude
、longitude
和 timezone
字段然后在 [=23= 时返回 WeatherLocation
的实例来解决我的问题] 字段使用 getter 访问。现在一切正常!
data class CurrentWeatherResponse(
// Tells GSON that the "currently" field of the JSON returned by the
// API should be tied with our CurrentWeatherEntry data class
@SerializedName("currently")
val currentWeatherEntry: CurrentWeatherEntry,
val latitude:Double,
val longitude:Double,
val timezone:String
) {
val location:WeatherLocation
get() = WeatherLocation(latitude,longitude,timezone,currentWeatherEntry.time)
}