Serializable和Parcelable的用法


物语.png

导言

做Android开发的,相信大家都知道,Activity、Fragment之间的数据传递都是通过Bundle对象进行的。
而Bundle的Api中除了一些基本类型的方法之外,还有两个特殊的方法:

/**
     * Inserts a Parcelable value into the mapping of this Bundle, replacing
     * any existing value for the given key.  Either key or value may be null.
     *
     * @param key a String, or null
     * @param value a Parcelable object, or null
     */
    public void putParcelable(@Nullable String key, @Nullable Parcelable value) {
        unparcel();
        mMap.put(key, value);
        mFlags &= ~FLAG_HAS_FDS_KNOWN;
    }

/**
     * Inserts a Serializable value into the mapping of this Bundle, replacing
     * any existing value for the given key.  Either key or value may be null.
     *
     * @param key a String, or null
     * @param value a Serializable object, or null
     */
    @Override
    public void putSerializable(@Nullable String key, @Nullable Serializable value) {
        super.putSerializable(key, value);
    }

那么,Serializable和Parcelable分别是什么呢?

Serializable

简介

Serialization是java自带的类型,做序列化用(把一个对象转换为可存储或可传输的形式的过程),对象可以将其当前状态存储到本地、数据库,也可以在网络上传输。以后,可以从存储区中读取或反序列化对象的状态,重新创建该对象。
序列化的本质是将运行时的对象转换为二进制流,保存到流、内存或通过网络传输。

实现方式

对象序列化很简单,只需要,实现Serialization类。

package com.bs.trade.main.bean;

import java.io.Serializable;

/**
 * author : user_zf
 * date : 18/3/17
 * desc : 茶
 */
public class Tea implements Serializable {
    private static final long serialVersionUID = -1241963366850216618L;
    
    private String name;
    private String price;
    private String describe;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPrice() {
        return price;
    }

    public void setPrice(String price) {
        this.price = price;
    }

    public String getDescribe() {
        return describe;
    }

    public void setDescribe(String describe) {
        this.describe = describe;
    }
}

看源码可以发现,Serialization是一个空的接口,它的作用是标志当前类可以被ObjectOutputStream序列化,和被ObjectInputStream反序列化。
可以看到需要定义一个serialVersionUID变量,这个变量类似于接口版本号,标志了唯一一个可序列化的类。序列化过程会保存serialVersionUID,反序列化过程会校验版本号是否一致,如果不一致,会报InvalidClassException错误。
JVM规范强烈推荐手动声明一个版本号,AndroidStudio中可以设置Lint提示,自动生成版本号。如果不手动设置这个值,系统会生成一个默认hash值,一旦类结构发生改变,hash值对应改变,那么反序列化就会校验serialVersionUID失败。设置了固定值,即使类结构发生改变,也能最大程度上保证反序列化成功率。不过如果类名改变,那么反序列化过程中会crash。

用法

public void put() {
    Bundle bundle = new Bundle();
    Tea tea = new Tea();
    tea.setName("普洱");
    tea.setPrice("13");
    tea.setDescribe("清新可口,润喉滋养");
    bundle.putSerializable("TEA", tea);
}

public void get() {
    Tea tea = (Tea) bundle.getSerializable("TEA");
}

Parcelable

简介

Parcelable是Android专门提供类,实现的功能和Serialization一样,就是把对象转换为可存储和可传输的形式。不过原理同Serialization不同,Parcelable是把一个完整的对象分进行分解,每一部分都是Intent和Bundle支持的类型。

实现方式

package com.bs.trade.main.bean;


import android.os.Parcel;
import android.os.Parcelable;

/**
 * author : user_zf
 * date : 18/3/17
 * desc : 茶
 */
public class Tea implements Parcelable {
    private String name;
    private String price;
    private String describe;

    public Tea(){}

    private Tea(Parcel source) {
        name = source.readString();
        price = source.readString();
        describe = source.readString();
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);
        dest.writeString(price);
        dest.writeString(describe);
    }

    public static final Creator CREATOR = new Creator() {
        @Override
        public Tea createFromParcel(Parcel source) {
            return new Tea(source);
        }

        @Override
        public Tea[] newArray(int size) {
            return new Tea[size];
        }
    };

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPrice() {
        return price;
    }

    public void setPrice(String price) {
        this.price = price;
    }

    public String getDescribe() {
        return describe;
    }

    public void setDescribe(String describe) {
        this.describe = describe;
    }
}

要注意的是,字段读取的顺序和写入的顺序必须保持一致。

用法

public void put() {
    Bundle bundle = new Bundle();
    Tea tea = new Tea();
    tea.setName("普洱");
    tea.setPrice("13");
    tea.setDescribe("清新可口,润喉滋养");
    bundle.putParcelable("TEA", tea);
}

public void get() {
    Tea tea = bundle.getParcelable("TEA");
}

对比Serialization和Parcelable

  1. 在内存中使用的时候,Parcelable比Serialization性能高,推荐使用Parcelable,例如Activity、Fragment数据传递的场景
  2. Serialization会产生大量的临时变量,从而引起频繁的GC。
  3. Parcelable不能使用在将数据存储在磁盘的情况(如SD卡,网络传输),因为Parcelable不能很好的保证数据的持续性,此时推荐使用Serialization。

写于2018.03.17下午18:00(位置:深圳南山区)

你可能感兴趣的:(Serializable和Parcelable的用法)