简析Java中的Serializable与Android中的Parcelable序列化
文章目录
- 关于序列化
- Serializable
- 简述原理
- 怎么使用
- Parcelable
- Parcelable的实现原理
- “包装公司”Parcel
- 装包
- 拆包
- 小结
- Parcelable的使用
- 两者的区别
- Serializable
- Parcelable
- 总结
关于序列化
这篇文章主要来讲一下在安卓中关于序列化的问题。首先了解一个问题:什么是序列化?为什么要用到序列化?
- 什么是序列化:序列化就是就是把一个对象变成可传输的二进制流,可以进行传输。
- 什么是反序列化:与序列化对应,反序列化就是把一个二进制流转化成对象。
- 哪里用到序列化:上面说到序列化就是把对象变得可传输;例如在内存,或者网络中传输数据的时候,就得把一个对象变成二进制流可以进行传输。除此之外,在各种通信中,例如进程间通信,文件读取写入等等都要用到序列化。涉及到数据传输,就得使用序列化。因为只有二进制流才可以进行传输。
- 我们在那些地方会遇到序列化:我们会发现,仅有基本数据类型可以自动进行序列化,但是我的自定义对象并不可以进行序列化。在哪里可以体现呢?当我们从一个Activity向另外一个Activity传递数据的时候,通过Intent,我们会发现只能放基本数据类型。
- 怎么让自定义的对象可序列化:就是我们要讲的Serializable和Parcelable接口。这两个接口就可以让我们的自定义对象可序列化。
那这两个接口怎么使用?他们有什么区别?这就是接下来我要讲的。
Serializable
简述原理
Serializable只要使用Java的ObjectOutputStream与ObjectInputStream来开启流。而这个接口主要就是用来标识这个对象可以被转换。关于IO流的相关知识,读者有兴趣可以去深入了解,这里不做深入探究。
怎么使用
这个序列化接口是Java提供的,实现了这个接口的类,其实例就可以进行传输。那么这个接口怎么使用呢?
直接实现这个接口就行了。
因为这是一个空接口,所以使用方法极其简单,只需要实现这个接口即可。接下来看个例子:
public class Test implements Serializable {private String string1;private String string2;private int num;private Son son;private List<Son> list = new ArrayList<>();public String getString1() {return string1;}public void setString1(String string1) {this.string1 = string1;}public String getString2() {return string2;}public void setString2(String string2) {this.string2 = string2;}public int getNum() {return num;}public void setNum(int num) {this.num = num;}public Son getSon() {return son;}public void setSon(Son son) {this.son = son;}public List<Son> getList() {return list;}public void setList(List<Son> list) {this.list = list;}
}
这样就可以把这个Test对象序列化了。
Parcelable
同样是使对象可序列化,同样是继承接口,但是Parcelable相比Serializable就要复杂得多了。Paecelable需要在要序列化的类中利用Parcel重写序列化和反序列化的方法。
Parcelable的实现原理
Parcelable的实现原理主要就是在内存中开辟一个共享内存块,然后进行传输,看图:
如图在AB两个进程中要进行传输,不能直接把一个对象传输过去,开辟一块内存,通过Parcel,也就是打包的方式,把数据存在了共享内存,再把共享内存中的数据用Parcel取出来,实现数据传输。通俗点来讲,就像送外卖一样,商家找了外卖这个中间人,把食物打包给了外卖小哥,然后你再找外卖小哥拿外卖,再拆包就可以拿到食物了。
通过原理可以看到,实现这个接口的重点就在:装包,拆包。如果将对象里面的数据,一个个装起来,是我们要在类中实现的方法。而装拆包公司就是Parcel。所以首先来了解一下这个包装公司:Parcel!
“包装公司”Parcel
Parcel的使用和Intent是差不多的,就是write(put)进去,再read(get)出来。简单来看看怎么使用:
装包
直接上代码,相关方法说明看注释:
Parcel parcel;//打包字符串parcel.writeString(String string);//打包整型数parcel.writeInt(int num);//打包布尔变量,要和bite进行转换parcel.writeByte((byte) (boolean bl? 1 : 0));//打包字符串集合parcel.writeStringList(List<String> list);//ElemType表示一个自定义类//序列化对象的时候传入要序列化的对象和一个flag,这里的flag的意思是是否要将这个作为返回值返回//一般传入0,要作为返回值就写1。另外这个对象也一定要是可序列化的parcel.writeParcelable(ElemType elem, 0);//这里写入自定义元素集合有两种方法,区别是是否写入类的信息//第一种方法是不写入类信息,相对应的取出来的时候要用Parcel把元素里面的每一个元素拿出来parcel.writeTypedList(mFriends);//第二种方法是写入类的信息,取出来的时候就要用类加载器去加载parcel.writeList(mFriends);//同样也要保证集合的元素可序列化
这里可以看到整体和Intent的传入数据是十分像的。重点有三个地方不太一样:
- 布尔变量。布尔变量不能直接放进去,要转换成bite
- 可序列化对象。这个放进去的时候要保证这个对象是可序列化的,也就是必须实现序列化接口
- 集合。集合分为两种。一种是把元素类的信息也放进去,一种是不把元素的类的信息放进去。下面将拆包会详细讲一下。
拆包
直接上代码:(变量使用装包中的变量)
Parcel source;//这个对象在反序列化的时候会作为参数传入供给使用//获取字符串String string= source.readString();//获取整型int i = source.readInt();//获取布尔数boolean b = source.readByte() != 0;//这里注意转化//获取自定义对象// 读取对象需要提供一个类加载器去读取,因为写入的时候写入了类的相关信息ElemType e = source.readParcelable(ElemType.class.getClassLoader()); //获取字符串集合List<String> list = source.createStringArrayList();//这一类需要用相应的类加载器去获取//ElemType表示一个自定义类source.readList(List<Elemtype> list, ElemType.class.getClassLoader());//这一类需要使用自定义类的CREATOR,也就是使用Pacel的反序列方法去获取//source.readTypedList(ElemType e, ElemType.CREATOR); //对应writeTypeList//books = in.createTypedArrayList(ElemType.CREATOR); //对应writeTypeList
主要就是对于布尔变量以及集合的转换会比较不一样。
代码中的Friend.CREATOR是Parcelable接口中反序列的方法,实现原理也是用Parcel把对象里面的数据一个个转换出来。
- 布尔变量要进行转换
- 对象要用类加载器去加载。因为写入的时候写入了类信息
- 集合看情况;写入了类信息就要用类加载器;否则用反序列的方法。
小结
Parcel的使用方法和Intent很像,但是有几个点要注意一下:
- Parcel中没有布尔变量,所以必须将布尔变量和bite进行转换
- Parcel包装自定义对象时,这个对象对应的类必须也得是实现了序列化接口的才可以进行打包。装包的这个方法因为写入了类的信息,所以拆包的时候需要用到对应类的加载器来进行加载。
- Parcel在包装集合的时候有两种方法:一种是写入类的信息,一种是不写入类的信息。但都有一个前提:集合中的元素必须是可序列化的。第一种方法需要用到类加载器去加载,第二种就需要用到自定义类中的Parcel的反序列化方法。
- 对于类中有多个相同类型的数据,例如3个字符串,3个int等等,存入的顺序和取出来的顺序一定要一致。例如存int a,int b;那么取出来的时候也得是int a,int b。不能颠倒。
Parcelable的使用
看完了上面的Pacel可能还是有一点懵,那这个怎么Parcelable怎么用Pacel实现呢?Parcelable的主要实现思路就是把一个对象中的数据进行分解,分解出来的数据都是可以用Parcel打包的。Parcelable具体怎么使用呢?接下来就来看一下。先看看谷歌给出的示例(代码很重要,记得看注释):
//首先要实现Parcelable接口
public class MyParcelable implements Parcelable {//类中的数据private int mData;//接下来这两个方法是关于序列化的。一定要重写的两个方法//第一个方法是内容描述。一般没什么要求都是返回0就行了public int describeContents() {return 0;}//第二个是序列化数据的方法。当我们序列化这个类的对象的时候就会调用到这个方法//两个参数:一个是Pacel“包装公司”上面我们讲的,一个是flags。第二个参数表示是否把数据返回。一般为0.//利用这个Parcel把类中所有的数据“打包”序列化public void writeToParcel(Parcel out, int flags) {//这个就是上面我们介绍的Parcel的使用out.writeInt(mData);}//接下来的这两个就是关于反序列化的了//CREATOR是Parcelable中的一个静态变量,这个名字不能改,因为他内部调用的时候就是用CREATOR来调用的改了名字就找不到了//观察我们上面的Pacel使用方法也可以发现,是传入ElemType.CREATOR。如果改了名字就找不到了。//Creator对象中有两个方法要重写:public static final Creator<MyParceable> CREATOR= new Creator<MyParceable>() {//这个就是反序列方法了。在Pacel中把数据取出来构建成一个MyParcelable对象public MyParcelable createFromParcel(Parcel in) {//这里我们用到构造器来获取这个对象。具体构造器实现方法在下面return new MyParcelable(in);}//这个是开辟数组供给使用。一般按照下面的格式写就好了。public MyParcelable[] newArray(int size) {return new MyParcelable[size];}};//这个是构造器。从Parcel中把数据取出来 private MyParcelable(Parcel in) {//这里就用到了上面我们讲的Parcel的获取数据的方法了mData = in.readInt();}
通过上面的代码相信也可以很清晰的了解怎么实现了。主要就是分为两个部分:序列化和反序列化。
- 序列化主要就是用一个Parcel把数据封装起来。怎么使用按照上面的Parcel使用方法。
- 反序列化要用到一个静态变量,这也可以说是一个构造器,Creator本身就是创造的意思嘛。通过这个Creator吧Parcel中的数据取出来再构造成一个对象,对应拆包。具体我们使用构造器来实现。构造器里面用Parcel的获取数据方法来把数据取出来。需要注意的是这里的CREATOR名字不能改。
两者的区别
好了。到这里相信都了解怎么使用这两个接口了。主要是Parcelable比较复杂。现在有个问题了,为什么要造一个如此复杂的接口呢?来看看他们各自的优缺点。
Serializable
这个是java内部定义的序列化接口。
- 优点:使用范围广,在网络,内存文件等均可以使用;使用方式简单,仅仅只需要继承一个接口就可以使用。
- 缺点:性能差;序列化的时候需要创建很多的临时对象。
Parcelable
这个安卓中可以使用的接口,仅用于安卓。
- 优点:性能强大。开发者号称比Serialization强大10倍的性能。
- 缺点:实现过程复杂,需要把对象中的数据一个个拆开进行序列化;
从实现原理可以看出来,这个只能用于内存中的序列化,不能用于网络和本地硬盘文件。
总结
序列化在安卓开发中还是很常用的,例如活动之间传递信息,跨进程传递数据等等都要用到。这两个接口一个简单粗暴,一个复杂强大,平常开发的话,尽量还是使用第二个接口,毕竟多一点代码可以加强这么多的性能何乐不为呢。Parcelable可能比较难理解,多看几遍就可以了。不理解或者笔者写错的可以评论区留言。
简析Java中的Serializable与Android中的Parcelable序列化相关推荐
- android 序列化 xml serializable,关于Android中的序列化Serializable和Parcelable的学习
简单地说,"序列化"就是将运行时的对象状态转换成二进制,然后保存到流,内存或者通过网络传输给其他端. 两者最大的区别在于 存储媒介的不同,Serializable使用 I/O 读写 ...
- android Java开发设计模式及在android中的应用解析
android Java开发设计模式及在android中的应用解析 什么是设计模式: 可以用一句话概括设计模式---设计模式是一种利用OOP的封闭.继承和多态三大特性,同时在遵循单一职责原则.开闭原则 ...
- java除了android,Java中是否有类似android中的android.os.Handler的类?
没有一个默认.但是你可以让自己的自定义类来做类似的事情. 我做了一个这样的: import java.util.ArrayList; public class Handler extends Obje ...
- Java中beimage_GitHub - beconf/ImageBlurring: Android 中通过 Java 与 JNI 分别进行图片模糊;并且进行比较其运算速度。...
ImageBlurring Android 中通过 Java 与 JNI 分别进行图片模糊:并且进行比较其运算速度. 相关文章 备注消息 Screenshots RenderScript Fast B ...
- Java泛型应用之打造Android中ListView和GridView万能适配器【CommonAdapter】--超简洁写法
转载请注明出处:http://blog.csdn.net/linglongxin24/article/details/52813227 [DylanAndroid的csdn博客] 在android中使 ...
- 简析 Java语言的过载与重载
复习一下 : 过载 (override) 重载 (overload) 在代码实践中 理清概念. package sub;/*** 简析 过载与重载* User: yiminghe* Dat ...
- android androidruntime java,java – Runtime.exec():在Android中重启?
重新启动在Android中正常工作.你可能没有正确地执行runtime.exec(). 你需要处理 public static void rebootSU() { Runtime runtime = ...
- 【译】Android中的安全数据— Android中的加密(第2部分)
目录 锁屏 选择一个钥匙 密钥存储 密钥生成 密钥管理 加密与解密 使用范例 下一步是什么 安全提示 锁屏 如果要保护数据,请保护设备. 为了更加安全,在提供对任何应用程序功能的访问权限之前,我们可以 ...
- 【译】Android中的安全数据— Android中的加密(第1部分)
目录 Java密码体系结构 Android Key Store 样例项目 下一步是什么 安全提示 Java密码体系结构 Android建立在Java密码体系结构(JCA)的基础上,该体系结构提供了用于 ...
最新文章
- cto denalil
- Oculus和虚拟现实的无限可能
- 《Go语言圣经》学习笔记 第三章 基础数据类型
- oracle 多路径 SAN,前言 - Oracle Solaris 管理:SAN 配置和多路径
- java day12【Object类、常用API】
- 一道错误答案传遍全网的逻辑面试题
- javaweb不同用户登录不同页面的页面_ssh+mysql实现的Java web论坛系统源码附带视频指导运行教程...
- 数据结构 复习攻略 新手必看
- JAVA判断素数法+引用方法
- 《Revisiting Pre-trained Models for Chinese Natural Language Processing》(MacBERT)阅读记录
- 手机背景图片被删除怎么恢复
- Java将英文句子分解为单词
- PIA (Primary Interop Assembly) AIA (Alternate Interop Assembly)简介
- 第四章 大数定律与中心极限定理(总结)
- Linux tar/rpm/yum命令软件安装
- 开源PLM软件Aras详解六 角色与用户以及权限
- iOS app集成使用 Facebook 深度链接
- ABBYY FineReader 14扫描和保存文档
- illustrator下载_如何在Illustrator中创建光泽的圣诞摆设
- 通通通2006+浩方打星际问题