【Android学习】序列化:Serializable和Parcelable

1,Serializable

实现了Serializable接口的对象,可将它们转换成一系列字节,并可在以后完全恢复回原来的样子。这一过程亦可通过网络进行。这意味着序列化机制能自动补偿操作系统间的差异。

1)概念

①Serializable接口

完成对象的序列化过程,提供标准的反序列化和序列化操作。
序列化接口Serializable没有方法或字段,仅用于标识可序列化的语义。

②对象的序列化

指把对象转换为字节序列(二进制流)的过程。

用途:
a.将对象的字节序列永久地保存到硬盘上,通常存放在一个文件中(请注意三级缓存概念)
b.在网络上传送对象的字节序列。

③对象的反序列化

指把字节序列恢复为对象的过程。

④三级缓存(内存 磁盘 网络)

内存缓存就是app存活期间,将数据缓存在内存中。
磁盘缓存就是将数据请求写入sharedPreferences或者文件或者数据库。

应用:
微信的对话列表、朋友圈、微博等。
A.上次请求的数据,下次如果是同一个网络请求id就直接取内存的不从网络获取了。
B.断网的情况下,用户依然能够浏览之前请求的数据。
C.对于已经拿到列表数据,只是详情中的某些数据没有获取到,突然断网了,而用户依然能继续浏览一部分数据。
D.对于网页上的图片,如列表的图片等,缓存到内存,下次再没有网络的情况下打开app,依然有好的体验和显示。

说到这就要引入清除缓存的概念了。

清除缓存

2)场景

可能会触发频繁的IO操作,效率比较低,适合将对象存储到磁盘上的情况

3)实现

①序列化

A.实现Serializable接口;
B.在类中声明如下标识:

private static final long serialVersionUID = 1L;

在反序列化的时候,这个标识和当前类版本相同,才可成功反序列化。

即使不指定serialVersionUID也可以序列化成功,但在有些时候,却不行:如果不手动指定serialVersionUID,反序列化时如果当前类有所改变(增加或删除了某些成员变量),系统就会重新计算当前类的hash值并赋值给serialVersionUID,这个时候serialVersionUID就前后不一致,序列化失败。

②读写

被序列化的类需要实现Serializable接口,使用ObjectInputStream和ObjectOutputStream进行对象的读写。

4)可序列化对象

①8种基本数据类型及其数组

②String/CharSequence实例类型的数据及数组

String实现了Serializable。

③实现了Serializable的对象及数组

如:String 、 File、ArrayList、HashMap 实现了Serializable。

④实现了Parcelable的对象及数组

5)不能序列化的对象

①静态成员

静态成员变量属于类不属于对象。

② transient标记

被transient关键字标记的成员变量。

序列化有2种方式:
A、实现了Serializable接口。
序列化时,调用java.io.ObjectOutputStream的defaultWriteObject方法,将对象序列化。
注意:此时transient修饰的字段,不会被序列化。
B、实现了Serializable接口,同时提供了writeObject方法。
序列化时,会调用该类的writeObject方法。而不是java.io.ObjectOutputStream的defaultWriteObject方法。
注意:此时transient修饰的字段,是否会被序列化,取决于writeObject。

③Bitmap

不能被序列化,所以要通过Intent传递的时候,需要转换为Byte[]来传递。

2,Parcelable

1)概念

Parcelable接口同样提供对象的序列化过程。

Parcel被用作封装数据的容器,封装后的数据可以通过Intent或IPC传递。除了基本类型以外,只有实现了Parcelable接口的类才能被放入Parcel中。

2)场景

将序列化后的字节流写入到一个共性内存中,其他对象可以从这块共享内存中读出字节流,并反序列化成对象。因此效率比较高,适合在对象间或者进程间传递信息

3)使用

public class User implements Parcelable{
    private String name;
    private int age;

    protected User(Parcel in) {
        //Parcel内部包包含了可序列化的数据,可以在Binder中自由传输。
        name = in.readString();
        age = in.readInt();
    }

    public static final Creator<User> CREATOR = new Creator<User>() {//反序列化
        @Override
        public User createFromParcel(Parcel in) {//创建原始对象
            return new User(in);
        }

        @Override
        public User[] newArray(int size) {//创建指定长度的原始对象数组
            return new User[size];
        }
    };

    @Override
    public int describeContents() {//内容表述
        return 0;//一般为0,仅当当前对象中存在文件描述符时,此方法返回1.
    }

    @Override
    public void writeToParcel(Parcel parcel, int i) {//序列化。其中i:1标识当前对象需要作为返回值返回,不能立即释放资源。几乎所有情况都返回0.
        parcel.writeString(name);
        parcel.writeInt(age);
    }
}

4)对比Serializable、Parcelable对比

①Parcelable(推荐)

实现了Parcelable对象存放在内存中。
是Android中的序列化方式,实现麻烦,效率高,主要用于内存序列化。
Serializable在序列化的时候会产生大量的临时变量,从而引起频繁的GC。
在使用内存的时候,Parcelable比Serializable性能高。

②Serializable

实现了Serializable对象存放在本地文件中。
用于将对象序列化到存储设备、将对象序列化后通过网络传输。
是Java中的序列化接口,使用简单但开销很大,序列化和反序列化都需要大量I/O操作。
Parcelable不能使用在要将数据存储在磁盘上的情况,因为Parcelable不能很好的保证数据的持续性在外界有变化的情况下。尽管Serializable效率低点,但此时还是建议使用Serializable 。

3,应用

1)Intent传递

2)类的序列化

被序列化的类需要实现Serializable接口,使用ObjectInputStream和ObjectOutputStream进行对象的读写。

未实现此接口的类无法进行任何状态的序列化和反序列化。

类通过实现 java.io.Serializable 接口以启用其序列化功能。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值