Parcelable与Serializable浅析

简介

在Android中,有两种方法可以进行序列化操作,一是使用Java自带的Serializable,二是使用Android专有的Parcelable接口。实现Serializable或是Parcelable都能达到序列化的效果,那为何要进行序列化?

序列化通俗的解释,就是将有结构的对象转换成无结构的二进制文件,用于网络传输、文件存储到本地,或是在进程间进行传输。

Serializable对比Parcelable

Serializable的使用会涉及到反射,还有I/O的操作,Parcelable自己实现封送和解封,在效率上,Parcelable高于Serializable

Parcelable不能实现将数据保存在硬盘上这种情况,所以尽管Serializable效率偏低,但在这种情况还是得使用Serializable

Serializable的实现

Serializable通常以简单易用著称

public class NBAStar implements Serializable {
    private String name;

    public String getName() {
        return name;
    }

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

实体类只要实现Serializable接口,就能用于数据传输

Serializable使用方式

方式一,使用Intent传输

Intent nbaStarIntent =  new Intent(context,NBAStarActivity.class);
nbaStarIntent.putExtra("NBASTAR",nbaStar);
startActivity(nbaStarIntent);

方式二,使用Bundle传输

Intent nbaStarIntent =  new Intent(context,NBAStarActivity.class);
Bundle bundle = new Bundle();
bundle.putSerializable("NBASTAR",nbaStar);
nbaStarIntent.putExtras(bundle);
startActivity(nbaStarIntent);

Parcelable的实现

在具体实现Parcelable接口之前,我们先介绍一个概念,Parcel,那么什么是Parcel呢?

大家都知道在Android手机中,内存非常的宝贵,如何减少内存的消耗是永恒不变的真理,Parcel的设计也是一样,由于Serializable的序列化会导致过多的对象分配,以致于有时候会频繁的GC,那么便出现了Parcel,一种更加轻量级的高效的序列化和反序列化机制,更适用于Andorid基于Binder IPC机制的通信方式。Parcel通常意义上可以理解为包装各类数据的容器,而包装的方式就是通过实现Parcelable接口,这样数据就能在Binder中通过IPC机制传递,实现服务端与客户端的数据交互。


接下来看看如何实现Parcelable接口

public class NBAStar implements Parcelable {
    private String name;
    private String team;

    public String getName() {
        return name;
    }

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

    public String getTeam() {
        return team;
    }

    public void setTeam(String team) {
        this.team = team;
    }

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

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

    public static final Creator<NBAStar> CREATOR = new Creator<NBAStar>() {
        @Override
        public NBAStar createFromParcel(Parcel source) {
            NBAStar NBAStar = new NBAStar();
            NBAStar.setName(source.readString());
            NBAStar.setTeam(source.readString());
            return NBAStar;
        }

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

Parcelable的实现相比于Serializable会稍显复杂,主要分三个步骤

  • 序列化
这个过程通过重新writeTParcel()方法实现
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);
        dest.writeString(team);
    }

可以看到,Parcel直接调用writeString()方法实现对象内数据的序列化。其实Parcel实现各类基本数据的write方法,如writeInt(),writeLong(),writeFloat(),writeDouble()等

  • 反序列化
    public static final Parcelable.Creator<NBAStar1> CREATOR = new Creator<NBAStar1>() {

        @Override
        public NBAStar1 createFromParcel(Parcel source) {
            NBAStar NBAStar = new NBAStar();
            NBAStar.setName(source.readString());
            NBAStar.setTeam(source.readString());
            return NBAStar1;
        }

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

通过实例化匿名内部类Creator,创建名称为CREATOR的对象(这里名称不能更改为其他的),重写createFromParcel()方法,主要调用Parcel的readString()方法达到反序列化的效果。

  • 文件描述

describeContents()方法负责文件描述,通常情况下返回0即可,而其他唯一返回有效值,为CONTENTS_FILE_DESCRIPTOR(0x01),只有在使用DropBoxManager、ParcelFileDescriptor和InputChannel等用到这个值。

那文件描述符是什么呢?获取到文件描述符能做什么呢?大家知道在类UNIX系统中,一切皆是文件,文件描述符就是操作文件的数据结构,获取到文件描述符可以完成所有文件相关的操作。 因为文件描述符的作用如此之大,为了防止leak,需要禁止在Bundle传输Parcel时包含文件描述符,所以通过Parcel中包含ParcelFileDescriptor等在Bundle中使用时会抛出IllegalArgumentException。 所以,这个值是在系统内部进行安全保护所使用的,其他情况下填0即可。 

Parcelable使用方式

通过Bundle传递

Intent nbaStarIntent =  new Intent(context,NBAStarActivity.class);
Bundle bundle = new Bundle();
bundle.putParcelable("NBASTAR",nbaStar);
nbaStarIntent.putExtras(bundle);
startActivity(nbaStarIntent);

获取数据

getIntent().getParcelableExtra("NBASTAR")

Intent传递数据需要注意的事项

Intent中传值是基于Binder机制,当数据量过大时,会产生TransactionTooLargeException异常,下面是官方文档的解释

“The Binder transaction buffer has a limited fixed size, currently 1Mb, which is shared by all transactions in progress for the process. Consequently this exception can be thrown when there are many transactions in progress even when most of the individual transactions are of moderate size.”

即缓冲区最大1MB,并且这是该进程中所有正在进行中的传输对象所公用的,所以Intent传值数据大小不能超过1M。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值