Android java.lang.IllegalArgumentException:将JSON解析为kotlin数据类时,指定为非null的参数为null

Android java.lang.IllegalArgumentException:将JSON解析为kotlin数据类时,指定为非null的参数为null,android,json,kotlin,gson,Android,Json,Kotlin,Gson,在kotlin成为android的第一语言之后,我全身心地投入到它当中。随着这些天的一点进展,我已经将我现有的知识迁移到kotlin。最近,我在一个虚拟项目中学习如何使用GSON、改装和kotlin 这里CurrentWeather是在视图中显示数据的模型 data class CurrentWeather( val latitude: Double, val longitude: Double, val placeName: String, val temper

在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:9948 java.lang.IllegalArgumentException:指定为非null的参数为null:方法kotlin.jvm.internal.Intrinsics.checkParametersNotNull,参数p1 在bus.green.fivedayweather.ui.CurrentWeatherFragment$retrieveForecast$1.invokeUnknown来源:6 在bus.green.fivedayweather.ui.CurrentWeatherFragment$retrieveForecast$1.invokeCurrentWeatherFragment.kt:20 在bus.green.fivedayweather.net.OpenWeatherMapProvider$callbackwrapper.onResponseOpenWeatherMapProvider.kt:62

我在解析过程中是否做错了什么?

这是您的问题参数,指定为非null的参数为null。所有数据类都是使用非空参数构造函数声明的。然而,在解析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.
这是指定为非空的issue参数。所有数据类都是使用非空参数构造函数声明的。然而,在解析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.

我相信,如果按照上面的解决方案,将变量设置为可空类型,将无法解决问题。 在本例中,问题在于Gson本身的JSON解析。首先,Gson对Kotlin数据类没有本机支持。我建议你通读这篇文章。 这篇文章的简短总结如下

当我们考虑开发人员使用非可空类型时的零安全性时,这一点尤其糟糕。它将在运行时导致NullPointerException,IDE不会提示可能的nullability。在解析时我们甚至不会得到异常,因为Gson使用了不安全的反射,而Java并没有不可空类型的概念。 解决这个问题的一种方法是让步,让一切都可以为空,就像@Kingfisher Phuoc建议的答案一样。不幸的是,这不仅仅是让代码运行。原因是您的成员变量val currentWeather是数据类的实例,而使用reflect的Gson无法从反序列化的JSON中实例化它,因此即使您正确解析当前数据类的成员变量,它也将为null。 我的建议是切换到,它具有对Kotlin的内置支持。相反,如果您是Gson的超级粉丝,则需要在默认值的帮助下遵循此解决方法,并将变量设置为null类型。为此,我们基本上将构造函数参数设置为私有支持属性。然后,我们为每个具有实名的支持字段提供一个只读属性,并使用custom get=与Elvis运算符组合来定义默认值或行为,从而产生不可为空的返回值

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)
}

在我看来,在科特林统治世界的这些日子里,格森一直无法跟上步伐。如果你只是为了学习而做这个项目,你绝对应该使用Moshi。它有KotlinJsonAdapterFactory,它对JSON提供了开箱即用的支持。我相信,如果您遵循上述解决方案,将变量设置为可空类型,将不会解决您的问题。 在本例中,问题在于Gson本身的JSON解析。首先,Gson对Kotlin数据类没有本机支持。我建议你通读这篇文章。 这篇文章的简短总结如下

当我们考虑开发人员使用非可空类型时的零安全性时,这一点尤其糟糕。它将在运行时导致NullPointerException,IDE不会提示可能的nullability。在解析时我们甚至不会得到异常,因为Gson使用了不安全的反射,而Java并没有不可空类型的概念。 解决这个问题的一种方法是让步,让一切都可以为空,就像@Kingfisher Phuoc建议的答案一样。不幸的是,这不仅仅是让代码运行。原因是您的成员变量val current Weather是数据类的一个实例,而Gson使用reflect无法从反序列化的JSON中实例化它,因此即使您正确解析当前数据类的成员变量,它也将为null。 我的建议是切换到,它具有对Kotlin的内置支持。相反,如果您是Gson的超级粉丝,则需要在默认值的帮助下遵循此解决方法,并将变量设置为null类型。为此,我们基本上将构造函数参数设置为私有支持属性。然后,我们为每个具有实名的支持字段提供一个只读属性,并使用custom get=与Elvis运算符组合来定义默认值或行为,从而产生不可为空的返回值

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)
}
在我看来,在科特林统治世界的这些日子里,格森一直无法跟上步伐。如果你只是为了学习而做这个项目,你绝对应该使用Moshi。它有KotlinJsonAdapterFactory,它对JSON有现成的支持

你能发布你的方法retrieveForecast吗?什么调用它?这似乎就是stacktrace所指的,您可以发布您的方法retrieveForecast以及调用它的内容吗?这似乎就是stacktrace所指的