Android序列化

概念

序列化
将数据结构或者对象转换成二进制数据的过程;
反序列化
将二进制数据转换成数据结构或者对象的过程。

应用场景

1.网络传输
2.进程间通讯(进程间传递数据)
3.intent传输数据
4.数据持久化(保存到文件/数据库)

序列化方案

1.Serializable

空接口,起到标识作用,最简单的序列化方式,直接实现该接口即可,不需要实现任何方法。

细节

1. serialVersionUID
控制版本,主要是在反序列化的时候,jvm会对比二进制中的servialVersionUID和本地类文件中的servialVersionUID是否相同,相同则进行反序列化过程,不同直接抛出异常:

Exception in thread "main" java.io.InvalidClassException: com.ayy.enjoystudyhomework.serialiable.Student; local class incompatible: stream classdesc serialVersionUID = 994478117524975274, local class serialVersionUID = 994478117524975272

注意: 只要servialVersionUID相同就不会抛出以上异常,即使修改了类中的字段。

那么什么场景加,什么场景不加呢?
如果不手动指定 serialVersionUID,那么如果反序列化时相比序列化时的类结构发生了变动,那么jvm会重新计算(jvm自己的算法) serialVersionUID,导致序列化时的类和当前类的 serialVersionUID 值不一致,反序列化失败,抛出上述异常。

自动生成servialVersionUID
理解serialVersionUID

2.所有字段都要可序列化
基础类型(String,int,boolean,char等)已经默认实现的Serializable,如果类中有未实现Serializable的属性,序列化的时候会抛出以下异常:

Exception in thread "main" java.io.NotSerializableException: com.ayy.enjoystudyhomework.serialiable.Tag

3.transient
如果有些字段我就是不想实现序列化呢?可以忽略:
java:使用transient关键字修饰
koltin:使用@Transient注解
被transient(瞬间)修饰的字段或方法都是不被序列化的,也就是保存到本地和从本地读取的时候都不会操作这个字段。

4.静态变量不会被序列化
被static修饰的变量不会被序列化,因为我们序列化的是对象实例吗,而静态变量是属于类的。

5.自定义序列化和反序列化
类中定义writeObject和readObject方法可以自定义序列化逻辑。不太常用,了解即可。
从序列化流程图中可以看出我们可以干预其流程:
在这里插入图片描述

6.单例序列化
序列化和反序列化或破坏单例的唯一性。解决方法是在单例中定义readResolve方法返回单例对象:

public class SingleTon {
    private volatile static SingleTon instance;

    public static SingleTon getInstance() {
        if (instance == null) {
            synchronized (SingleTon.class) {
                if (instance == null) {
                    instance = new SingleTon();
                }
            }
        }
        return instance;
    }

    //定义此方法即可
    public SingleTon readResolve() {
        return this;
    }

}

序列化对单例模式的破坏

2.Externalizable

此接口继承自Serializable,可定制化序列化和反序列化过程,类似上面细节中的第五点

3.Parcelable

安卓特有的序列化方式,底层做了优化,性能较好,内存开销较小。
实现此接口,代码提示快捷键生成对应代码。

class Dog(var name: String?, var age: Int) : Parcelable {
    constructor(parcel: Parcel) : this(
        parcel.readString(),
        parcel.readInt()
    )

    override fun writeToParcel(parcel: Parcel, flags: Int) {
        parcel.writeString(name)
        parcel.writeInt(age)
    }

    override fun describeContents(): Int {
        return 0
    }

    companion object CREATOR : Parcelable.Creator<Dog> {
        override fun createFromParcel(parcel: Parcel): Dog {
            return Dog(parcel)
        }

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

Serializable和Parcelable那个性能比较好?为什么?
1.Parcelable性能相对较好
2.内存上Parcelable较小
3.Serializable序列化过程中使用了反射,会产生很多临时变量,影响性能
4.安卓专有,基于binder机制

遗留问题:
1.Parcelable不能很好的保证数据的持续性,为什么?
2.Parce还需深入理解
3.多引用问题:reser&&writeUnshare

总结

1.保存数据到 SD 卡,网络传输时使用 Serializable 即可,虽然效率差一些,好在使用方便。

2.运行时数据传递建议使用 Parcelable,比如 Intent,Bundle 等,Android 底层做了优化处理,效率很高。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值