Kotlin中泛型的序列化Parcelable

系列文章全部为本人的学习笔记,若有任何不妥之处,随时欢迎拍砖指正。如果你觉得我的文章对你有用,欢迎关注我以及我的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 = object : Parcelable.Creator {
            override fun createFromParcel(source: Parcel): PersonData {
                return PersonData(source)
            }

            override fun newArray(size: Int): Array {
                return arrayOfNulls(size)
            }
        }
    }
}

值得一提的是,在我写《Kotlin学习笔记(9)- 数据类》的时候,也确实只能这么写。但是现在AS上已经有了自动序列化的插件:在AS的Settings中选择Plugins,然后搜索“Parcelable Code Generator(for kotlin)”,安装即可。相信很多朋友用过它的Andorid版,使用方法基本是一样的,使用效果如图:

效果图

二、泛型的序列化

泛型就不必多说了,我在《Kotlin学习笔记(10)- 泛型》也详细的讲过了(这广告太自然了,哇咔咔),个人使用最多的场景应该就是处理服务器返回的结果了吧。如果恰巧这个结果模型需要在Activity间传递,那么是不是就要考虑泛型的序列化了呢?首先看看我是怎么实现的:

data class Resp(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).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> = object : Parcelable.Creator> {
            override fun createFromParcel(source: Parcel): Resp {
                return Resp(source)
            }

            override fun newArray(size: Int): Array?> {
                return arrayOfNulls(size)
            }
        }
    }
}

要注意以下几点:

  1. 泛型T一定要显式的声明可序列化,也就是我的泛型类型

  2. 数据流的声明参数中,泛型参数一定要有默认值,通常是默认null。我的习惯是全部参数都给默认值,这样可以有一个无参的构造函数。

  3. 我们通过保存泛型类型的方式,来达到无法获取泛型的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)
    } 
    

你可能感兴趣的:(Kotlin中泛型的序列化Parcelable)