系列文章全部为本人的学习笔记,若有任何不妥之处,随时欢迎拍砖指正。如果你觉得我的文章对你有用,欢迎关注我以及我的Kotlin专题,我们一起学习进步!
终于有一篇Kotlin文章不是沿袭了之前的笔记系列,这是尝试将Kotlin用到项目中遇到的第一个问题:如何将Kotlin中的泛型进行序列化?这个问题我们分两步解决:
- 一般数据类(
data class
)的序列化 - 泛型的序列化
一、一般数据类(data class
)的序列化
这个问题在我之前的文章《Kotlin学习笔记(9)- 数据类》中提到过,这里再说一下,在kotlin中序列化的实现方法和java中的手动实现基本一致
data class PersonData(var name : String, var age : Int, val sex : String) : Parcelable{
override fun writeToParcel(p0: Parcel?, p1: Int) {
p0?.writeString(this.name)
p0?.writeInt(this.age)
p0?.writeString(this.sex)
}
override fun describeContents(): Int {
return 0
}
constructor(source: Parcel) : this(source.readString(), source.readInt(), source.readString())
companion object {
@JvmField val CREATOR: Parcelable.Creator<PersonData> = object : Parcelable.Creator<PersonData> {
override fun createFromParcel(source: Parcel): PersonData {
return PersonData(source)
}
override fun newArray(size: Int): Array<PersonData?> {
return arrayOfNulls(size)
}
}
}
}
值得一提的是,在我写《Kotlin学习笔记(9)- 数据类》的时候,也确实只能这么写。但是现在AS上已经有了自动序列化的插件:在AS的Settings中选择Plugins,然后搜索“Parcelable Code Generator(for kotlin)”,安装即可。相信很多朋友用过它的Andorid版,使用方法基本是一样的,使用效果如图:
二、泛型的序列化
泛型就不必多说了,我在《Kotlin学习笔记(10)- 泛型》也详细的讲过了(这广告太自然了,哇咔咔),个人使用最多的场景应该就是处理服务器返回的结果了吧。如果恰巧这个结果模型需要在Activity间传递,那么是不是就要考虑泛型的序列化了呢?首先看看我是怎么实现的:
data class Resp<T: Parcelable>(var code: Int = 0,
var msg: String = "",
var data: T? = null)
: Parcelable {
val EMPTY = "empty"
constructor(source: Parcel) : this() {
code = source.readInt()
msg = source.readString()
val className = source.readString()
data = if(className == EMPTY) null else source.readParcelable(Class.forName(className).getClassLoader())
}
fun classLoader() : ClassLoader {
val type = javaClass.genericSuperclass
val params = (type as ParameterizedType).actualTypeArguments
return (params[0] as Class<T>).classLoader
}
override fun describeContents(): Int {
return 0
}
override fun writeToParcel(dest: Parcel, flags: Int) {
dest.writeInt(this.code)
dest.writeString(this.msg)
dest.writeString(if(this.data==null) EMPTY else this.data!!::class.java.name)
dest.writeParcelable(this.data, flags)
}
companion object {
@JvmField val CREATOR: Parcelable.Creator<Resp<Parcelable>> = object : Parcelable.Creator<Resp<Parcelable>> {
override fun createFromParcel(source: Parcel): Resp<Parcelable> {
return Resp<Parcelable>(source)
}
override fun newArray(size: Int): Array<Resp<Parcelable>?> {
return arrayOfNulls(size)
}
}
}
}
要注意以下几点:
泛型
T
一定要显式的声明可序列化,也就是我的泛型类型<T: Parcelable>
。数据流的声明参数中,泛型参数一定要有默认值,通常是默认
null
。我的习惯是全部参数都给默认值,这样可以有一个无参的构造函数。-
我们通过保存泛型类型的方式,来达到无法获取泛型的
ClassLoader
的问题。也就是这篇文章的最重要的点:constructor(source: Parcel) : this() { ... val className = source.readString() data = if(className == EMPTY) null else source.readParcelable(Class.forName(className).getClassLoader()) } override fun writeToParcel(dest: Parcel, flags: Int) { ... dest.writeString(if(this.data==null) EMPTY else this.data!!::class.java.name) dest.writeParcelable(this.data, flags) }