我最近将Java模型类迁移到Kotlin Data类。我使用@Parcelize注释来避免Parcelable的样板代码。我在Kotlin中的数据类如下所示,
@Parcelize
data class TimeLine(
@SerializedName("submittedOnDate")
var submittedOnDate: List<Int> = ArrayList(),
@SerializedName("submittedByUsername")
var submittedByUsername: String,
@SerializedName("submittedByFirstname")
var submittedByFirstname: String,
@SerializedName("submittedByLastname")
var submittedByLastname: String,
@SerializedName("approvedOnDate")
var approvedOnDate: List<Int> = ArrayList(),
@SerializedName("approvedByUsername")
var approvedByUsername: String,
@SerializedName("approvedByFirstname")
var approvedByFirstname: String,
@SerializedName("approvedByLastname")
var approvedByLastname: String,
@SerializedName("activatedOnDate")
var activatedOnDate: List<Int>,
@SerializedName("activatedByUsername")
var activatedByUsername: String,
@SerializedName("activatedByFirstname")
var activatedByFirstname: String,
@SerializedName("activatedByLastname")
var activatedByLastname: String,
@SerializedName("closedOnDate")
var closedOnDate: List<Int>) : Parcelable`
但是它给了我空指针错误,如下所示,
java.lang.NullPointerException: Attempt to invoke interface method 'int
java.util.Collection.size()' on a null object reference at
org.demo.mobile.models.accounts.savings.TimeLine.writeToParcel(TimeLine.kt:0)
at org.demo.mobile.models.accounts.savings.SavingAccount.writeToParcel(SavingAccount.kt:0)
我不知道为什么它显示NullPointerException,因为Java Model运行正常。我该如何解决?NPE的背后原因是什么?
答案 0 :(得分:2)
GSON使用不安全的API来构造您的对象-能够在您声明非空类型的地方放置null。生成的Parcelable实现期望非空值。当您尝试将对象放到包裹中时,它会崩溃。
我看到两个选择:
您将所有属性声明为var
。您可以创建一个扩展方法,为您修复非空值。
@Suppress("SENSELESS_COMPARISON")
fun TimeLine.fixNulls() {
if (submittedOnDate == null) submittedOnDate = emptyList()
if (approvedOnDate == null) submittedOnDate = emptyList()
if (activatedOnDate == null) submittedOnDate = emptyList()
if (closedOnDate == null) submittedOnDate = emptyList()
}
示例:
val list = gson.fromJson(...).forEach { it.fixNulls() }
或者如果您具有具有val
属性的不可变类型:
fun TimeLine.withFixedNulls() = copy(
submittedOnDate = submittedOnDate ?: emptyList(),
approvedOnDate = approvedOnDate ?: emptyList(),
activatedOnDate = activatedOnDate ?: emptyList(),
closedOnDate = closedOnDate ?: emptyList()
)
示例:
val list = gson.fromJson(...).map { it.withFixedNulls() }
缺点是您必须考虑这一点,并记住在从GSON获得的每个对象上调用它。
这两个变体都有其他问题(内存消耗,并发性)。
您可以使用Moshi Kotlin Codegen。 Moshi与GSON一样,是一个序列化库,但其Kotlin Codegen注释处理器将为您的类型生成特殊的JSON适配器,如果您尝试将null反序列化为不可为null的属性,则会抛出异常。
当您尝试反序列化无效JSON时,它将引发异常,而不是当您尝试使用Kotlin / Java对象时。
免责声明:我只使用了基于相同原理的Moshi + Kotshi。
我将把练习作为练习留给您。
您不应将大型对象或大量对象放入宗地/意图中。有大小限制。也许您应该使用数据库。
答案 1 :(得分:1)
@Parcelize
data class TimeLine(
@field:SerializedName("via")
val via: MutableList<Int>? = null,
@field:SerializedName("submittedByUsername")
val submittedByUsername: String?= null
......... so on...
):Parcelable
您的数据模型类与此类似,您需要添加吗? (空安全性)运算符,以便它将接受空值。 有关Null安全性的更多详细信息,请访问Kotlin official documentation
答案 2 :(得分:0)
我遇到了这个问题,发现我的数据类中的一个不可为空的属性在json上收到了空值。
我的数据类:
@Parcelize
data class Person(
@SerializedName("first_name") val firstName: String,
@SerializedName("middle_name") val middleName: String,
@SerializedName("last_name") val lastName: String,
@SerializedName("birth_date") val birth: String,
@SerializedName("education") val education: List<Education> // <-- non-nullable property
) : Parcelable {
@Parcelize
data class Education(
@SerializedName("course") val course: String?,
@SerializedName("school") val school: String?,
) : Parcelable
}
JSON:
[
{
"first_name": "Steve",
"middle_name": "James",
"last_name": "Roberson",
"birth_date": "March 28, 1960",
"education": [
{
"course": "Course 1",
"school": "School 1",
},
{
"course": "Course 2",
"school": "School 2",
}
]
},
{
"first_name": "Michael",
"middle_name": "Ong",
"last_name": "Reyes",
"birth_date": "March 28, 1960",
"education": null // <-- this caused the error
},
...
]
因此,我通过添加?
将该属性声明为可空类型,它解决了该问题。
@SerializedName("education") val education: List<Education>?
根据您的情况,我认为您要解析的JSON具有空值会导致异常。