java.lang.IollegalArgumentException:在将JSON解析为kotlin Data类时,指



在kotlin成为android的第一种语言后,我全身心地投入到它中。随着这些天的一点进展,我一直在将我现有的知识迁移到kotlin中。最近,我正在学习如何在一个虚拟项目中使用GSON、改装和kotlin。

这里CurrentWeather是在视图中显示数据的模型

data class CurrentWeather(
    val latitude: Double,
    val longitude: Double,
    val placeName: String,
    val temperature: Float,
    val maxTemperature: Float,
    val minTemperature: Float,
    val windSpeed: Float,
    val windDirection: Float,
    val weatherType: String,
    val weatherDescription: String,
    val icon: String,
    val timestamp: Instant)

Current负责将JSON解析为POJO类,就像我过去所做的那样,但现在使用kotlin 看起来有点不同

data class Current(@SerializedName("coord") val location: Location,
          @SerializedName("weather") val weather: List<Weather>,
          @SerializedName("main") val temperatureAndPressure: TemperatureAndPressure,
          @SerializedName("wind") val wind: Wind,
          @SerializedName("dt") val timeStamp: Long,
          @SerializedName("name") val placeName: String) {
val time: Instant by fastLazy { Instant.ofEpochSecond(timeStamp) }

val currentWeather = CurrentWeather(location.latitude,
        location.longitude,
        placeName,
        temperatureAndPressure.temperature,
        temperatureAndPressure.maxTemperature,
        temperatureAndPressure.minTemperature,
        wind.windSpeed ?: 0f,
        wind.windAngle ?: 0f,
        weather[0].main,
        weather[0].description,
        weather[0].icon,
        time)
 }

即使我从改造中得到了成功的响应(我已经检查了成员变量;例如位置:位置,天气:列表,温度和压力:温度和压力等。然而,我收到了这个错误。

2018-11-12 21:04:07.455 9948-9948/bus.green.fivedayweather E/AndroidRuntime:致命异常:main流程:bus.green.fivedayweather,PID:9948java.lang.IollegalArgumentException:指定为非null的参数为null:方法kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull,参数p1在bus.green.feedayweather.ui.CurrentWeatherFragment$retrieveForecast$1.ioke(未知来源:6(在bus.green.feedayweather.ui.CurrentWeatherFragment$retrieveForecast$1.ioke(CurrentWeatherFragment.kt:20(在bus.green.feedayweather.net上。OpenWeatherMapProvider$ReformationCallbackWrapper.onResponse(OpenWeatherMapProvider.kt:62(

我在解析时做错了什么吗?

这是您的问题Parameter specified as non-null is null。所有的数据类都是用non-null parameter constructor声明的。然而,在解析JSON过程中,有一个null参数-->导致崩溃。为了解决这个问题,您应该声明构造函数参数为null,如下所示:

data class Current(@SerializedName("coord") val location: Location?,
      @SerializedName("weather") val weather: List<Weather>?,
      @SerializedName("main") val temperatureAndPressure: TemperatureAndPressure?,
      @SerializedName("wind") val wind: Wind?,
      @SerializedName("dt") val timeStamp: Long?,
      @SerializedName("name") val placeName: String?) {
// your CurrentWeather class should be the same. 
// Of course, if you are sure with non-null parameters, you should make them non-null.

我相信,如果按照上面的解决方案,使变量的类型可以为null,并不能解决您的问题。在您的案例中,问题在于Gson本身的JSON解析。首先,Gson没有对Kotlin数据类的原生支持。我建议你通读这篇文章GSON+KOTLIN。这篇文章的简短摘要是

  1. 当我们考虑到开发人员在使用不可为null的类型时对null安全性的假设时,这一点尤其糟糕。它将在运行时导致NullPointerException,IDE没有提示可能的可为null性。在解析时,我们甚至不会得到异常,因为Gson使用了不安全的反射,而Java并没有不可为null的类型的概念
  2. 处理这一问题的一种方法是让步,让一切都可以为空,就像@Kingfisher Phuoc提出的答案一样。不幸的是,这不仅仅是让代码运行。原因是您的成员变量val currentWeather是数据类的实例,而使用reflect的Gson无法从取消序列化的JSON中实例化它,因此即使您正确解析了data class Current的成员变量,它也将为null

我的建议是切换到Moshi,它内置了对Kotlin的支持。相反,如果你是Gson的超级粉丝,你需要在默认值和使变量为null类型的帮助下遵循这个解决方法。为此,我们基本上将构造函数参数设置为私有支持属性。然后,我们为每个具有真实名称的支持字段提供一个只读属性,并使用自定义get((=与Elvis运算符组合来定义我们的默认值或行为,从而产生不可为null的返回值。

data class Current(@SerializedName("coord") val _location: Location?,
      @SerializedName("weather") val _weather: List<Weather>?,
      @SerializedName("main") val _temperatureAndPressure: TemperatureAndPressure?,
      @SerializedName("wind") val _wind: Wind?,
      @SerializedName("dt") val _timeStamp: Long?, = 0.0
      @SerializedName("name") val _placeName: String? = "") {

val location
   get() = _location ?: throw IllegalArgumentException("Location is required")
val weather
   get() = _weather ?: throw IllegalArgumentException("Title is required")
val wind
   get() = _wind ?: throw IllegalArgumentException("Title is required")
val temperatureAndPressure
   get() = _temperatureAndPressure ?: throw IllegalArgumentException("Title is required")
......and so on

val time: Instant by fastLazy { Instant.ofEpochSecond(timeStamp) }

val currentWeather = CurrentWeather(location.latitude,
    location.longitude,
    placeName,
    temperatureAndPressure.temperature,
    temperatureAndPressure.maxTemperature,
    temperatureAndPressure.minTemperature,
    wind.windSpeed ?: 0f,
    wind.windAngle ?: 0f,
    weather[0].main,
    weather[0].description,
    weather[0].icon,
    time)
}

在我看来,在科特林统治世界的这些日子里,Gson没能跟上步伐。如果你只是为了学习而做这个项目,你绝对应该使用Moshi它有KotlinJsonAdapterFactory,它开箱即用地支持JSON

最新更新