Kotlin中泛型的序列化Parcelable

(转载)http://www.jianshu.com/p/e4bb5e23d9f5

系列文章全部为本人的学习笔记,若有任何不妥之处,随时欢迎拍砖指正。如果你觉得我的文章对你有用,欢迎关注我以及我的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)
            }
        }
    }
}

要注意以下几点:

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

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


作者:我爱吃栗子啊
链接:http://www.jianshu.com/p/e4bb5e23d9f5
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值