Android数据序列化总结
目录介绍
- 1.序列化简单介绍
- 1.1 序列化的概念
- 1.2 序列化是做什么用的
- 1.3 序列化的目的
- 2.Serializable的使用
- 2.1 什么是Serializable
- 2.2 Serializable简单实现
- 3.Parcelable的使用
- 3.1 什么是Parcelable
- 3.2 Parcelable简单实现
- 4.Parcelable与Serializable的性能比较
- 4.1 Serializable性能分析
- 4.2 Parcelable性能分析
- 4.3 性能比较总结描述
- 4.4 性能测试方法分析
- 4.5 两种如何选择
- 5.数据的序列化方案
- 5.1 数据序列化基础
- 5.2 SQLite
- 5.3 SharedPreferences
- 5.4 JSON
- 6.其他使用
- 6.1 Intent传递数据
- 7.其他介绍
- 7.1 参考链接
- 7.2 更新日志
- 7.3 我的博客
好消息
- 博客笔记大汇总【16年3月到至今】,包括Java基础及深入知识点,Android技术博客,Python学习笔记等等,还包括平时开发中遇到的bug汇总,当然也在工作之余收集了大量的面试题,长期更新维护并且修正,持续完善……开源的文件是markdown格式的!同时也开源了生活博客,从12年起,积累共计47篇[近20万字],转载请注明出处,谢谢!
- 链接地址:https://github.com/yangchong211/YCBlogs
- 如果觉得好,可以star一下,谢谢!当然也欢迎提出建议,万事起于忽微,量变引起质变!
0.备注
- 建议结合代码,看博客更加高效,项目地址:https://github.com/yangchong211/
- 博客大汇总,持续更新目录说明,记录所有开源项目和博客
1.序列化的概念
1.1 序列化的概念
- 序列化是将Java对象转化成字节序列的过程
- 反序列化是将字节序列恢复为Java对象的过程
- 看到网上还有种说法:序列化的意思笼统的来说就是将对象转化成二进制,用于在文件或者网络上进行传输;反序列化就是相反,将序列化后的二进制转换成可以看懂的对象。
1.2 序列化是做什么用的
- 无论是在进程间通信、本地数据存储又或者是网络数据传输都离不开序列化的支持。而针对不同场景选择合适的序列化方案对于应用的性能有着极大的影响。
- 从广义上讲,数据序列化就是将数据结构或者是对象转换成我们可以存储或者传输的数据格式的一个过程,在序列化的过程中,数据结构或者对象将其状态信息写入到临时或者持久性的存储区中,而在对应的反序列化过程中,则可以说是生成的数据被还原成数据结构或对象的过程。
- 这样来说,数据序列化相当于是将我们原先的对象序列化概念做出了扩展,在对象序列化和反序列化中,我们熟知的有两种方法,其一是Java语言中提供的Serializable接口,其二是Android提供的Parcelable接口。而在这里,因为我们对这个概念做出了扩展,因此也需要考虑几种专门针对数据结构进行序列化的方法,如现在那些个开放API一般返回的数据都是JSON格式的,又或者是我们Android原生的SQLite数据库来实现数据的本地存储,从广义上来说,这些都可以算做是数据的序列化。
1.3 序列化的目的
- (1).永久的保存对象数据(将对象数据保存在文件当中,或者是磁盘中
- (2).通过序列化操作将对象数据在网络上进行传输(由于网络传输是以字节流的方式对数据进行传输的.因此序列化的目的是将对象数据转换成字节流的形式)
- (3).将对象数据在进程之间进行传递(Activity之间传递对象数据时,需要在当前的Activity中对对象数据进行序列化操作.在另一个Activity中需要进行反序列化操作讲数据取出)
- (4).Java平台允许我们在内存中创建可复用的Java对象,但一般情况下,只有当JVM处于运行时,这些对象才可能存在,即,这些对象的生命周期不会比JVM的生命周期更长(即每个对象都在JVM中)但在现实应用中,就可能要停止JVM运行,但有要保存某些指定的对象,并在将来重新读取被保存的对象。这是Java对象序列化就能够实现该功能。(可选择入数据库、或文件的形式保存)
- (5).序列化对象的时候只是针对变量进行序列化,不针对方法进行序列化.
- (6).在Intent之间,基本的数据类型直接进行相关传递即可,但是一旦数据类型比较复杂的时候,就需要进行序列化操作了.
2.Serializable的使用
2.1 什么是Serializable
- 正如前面提到的,Serializable接口是Java语言的特性,是最简单也是使用最广泛的序列化方案之一,这边需要注意的一点是Serializable接口是一个标识接口,无需实现方法,Java便会对这个对象进行序列化操作。
- 在这里实现了Serializable接口的对象才可以序列化,将Java对象转换成字节序列,而对应的反序列化则是将字节序列恢复成Java对象的过程。
- 在需要序列化的类中会用到serialVersionUID去标识这个序列化对象,即仅当序列化后的数据中的SerialVersionUID与当前类的serialVersionUID相同时才能被正常的反序列化。
2.2 Serializable简单实现
- 需要注意的:静态成员变量是属于类而不属于对象的,所以显然它不会参与到对象的序列化过程中。其次用transient关键字标记的成员变量不参与到序列化过程中。最后,这种序列化方式是基于磁盘或者网络的。
public class Person implements Serializable{
private static final long serialVersionUID = -7060210544600464481L;
private String name;
private int age;
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
public int getAge(){
return age;
}
public void setAge(int age){
this.age = age;
}
}
3.Parcelable的使用
3.1 什么是Parcelable
- Parcelable是Android SDK提供的,它是基于内存的,由于内存读写速度高于硬盘,因此Android中的跨进程对象的传递一般使用Parcelable。
3.2 Parcelable简单实现
- Android Parcelable code generator可以使用这个插件
- 可以看出,实现一个Parcelable接口,需要实现以下几个方法:
- 1.构造函数:从序列化后的对象中创建原始对象
- 2.describeContents :接口内容的描述,一般默认返回0即可
- 3.writeToParcel:序列化的方法,将类的数据写到parcel容器中
- 4.静态的parcelable.Creator接口,这个接口包含两个方法
- 1)createFormParcel:反序列化的方法,将Parcel还原成Java对象
- 2)newArray:提供给外部类反序列化这个数组使用。
- Android Parcelable code generator可以使用这个插件
public class Book implements Parcelable{
private String bookName;
private String author;
private int publishDate;
public Book(){
}
//写一个构造方法或者set方法来方便写入数据
public String getBookName(){
return bookName;
}
public void setBookName(String bookName){
this.bookName = bookName;
}
public String getAuthor(){
return author;
}
public void setAuthor(String author){
this.author = author;
}
public int getPublishDate(){
return publishDate;
}
public void setPublishDate(int publishDate){
this.publishDate = publishDate;
}
@Override
public int describeContents(){
return 0;
}
@Override
public void writeToParcel(Parcel out, int flags){
//该方法将类的数据写入外部提供的Parcel中.即打包需要传递的数据到Parcel容器保存,
//以便从parcel容器获取数据
out.writeString(bookName);
out.writeString(author);
out.writeInt(publishDate);
}
public static final Parcelable.Creator<Book> CREATOR = new Creator<Book>(){
@Override
public Book[] newArray(int size){
//从Parcel容器中读取传递数据值,封装成Parcelable对象返回逻辑层。
return new Book[size];
}
@Override
public Book createFromParcel(Parcel in){
//从Parcel容器中读取传递数据值,封装成Parcelable对象返回逻辑层。
return new Book(in);
}
};
public Book(Parcel in){
//如果元素数据是list类型的时候需要: lits = new ArrayList<?> in.readList(list);
//否则会出现空指针异常.并且读出和写入的数据类型必须相同.如果不想对部分关键字进行序列化,可以使用transient关键字来修饰以及static修饰.
bookName = in.readString();
author = in.readString();
publishDate = in.readInt();
}
}
4.Parcelable与Serializable的性能比较
- 4.1 Serializable性能分析
- Serializable是Java中的序列化接口,其使用起来简单但开销较大(因为Serializable在序列化过程中使用了反射机制,故而会产生大量的临时变量,从而导致频繁的GC),并且在读写数据过程中,它是通过IO流的形式将数据写入到硬盘或者传输到网络上。
4.2 Parcelable性能分析
- Parcelable则是以IBinder作为信息载体,在内存上开销比较小,因此在内存之间进行数据传递时,推荐使用Parcelable,而Parcelable对数据进行持久化或者网络传输时操作复杂,一般这个时候推荐使用Serializable。
4.3 性能比较总结描述
- 首先Parcelable的性能要强于Serializable的原因我需要简单的阐述一下
- 1). 在内存的使用中,前者在性能方面要强于后者
- 2). 后者在序列化操作的时候会产生大量的临时变量,(原因是使用了反射机制)从而导致GC的频繁调用,因此在性能上会稍微逊色
- 3). Parcelable是以Ibinder作为信息载体的.在内存上的开销比较小,因此在内存之间进行数据传递的时候,Android推荐使用Parcelable,既然是内存方面比价有优势,那么自然就要优先选择.
- 4). 在读写数据的时候,Parcelable是在内存中直接进行读写,而Serializable是通过使用IO流的形式将数据读写入在硬盘上.
- 但是:虽然Parcelable的性能要强于Serializable,但是仍然有特殊的情况需要使用Serializable,而不去使用Parcelable,因为Parcelable无法将数据进行持久化,因此在将数据保存在磁盘的时候,仍然需要使用后者,因为前者无法很好的将数据进行持久化.(原因是在不同的Android版本当中,Parcelable可能会不同,因此数据的持久化方面仍然是使用Serializable)
4.4 性能测试方法分析
- 1)、通过将一个对象放到一个bundle里面然后调用Bundle#writeToParcel(Parcel, int)方法来模拟传递对象给一个activity的过程,然后再把这个对象取出来。
- 2)、在一个循环里面运行1000 次。
- 3)、两种方法分别运行10次来减少内存整理,cpu被其他应用占用等情况的干扰。
- 4)、参与测试的对象就是上面的相关代码
- 5)、在多种Android软硬件环境上进行测试
4.5 两种如何选择
- a)在使用内存方面,Parcelable比Serializable性能高,所以推荐使用Parcelable。
- b)Serializable在序列化的时候会产生大量的临时变量,从而引起频繁的GC。
- c)Parcelable不能使用在要将数据存储在磁盘上的情况,因为Parcelable不能很好的保证数据的持续性,在外界有变化的情况下,建议使用Serializable。
5.数据的序列化方案
5.1 数据序列化基础
- 下面讲到的是广义上的序列化方案,不同于前面两种狭义或者说是对象序列化方案,接下来的几种方案针对于数据的传输和存储过程中的序列化方案。
5.2 SQLite
- SQLite主要用于存储复杂的关系型数据,Android支持原生支持SQLite数据库相关操作(SQLiteOpenHelper),不过由于原生API接口并不友好,所以产生了不少封装了SQLite的ORM框架。
5.3 SharedPreferences
- SharedPreferences是Android平台上提供的一个轻量级存储API,一般用于存储常用的配置信息,其本质是一个键值对存储,支持常用的数据类型如boolean、float、int、long以及String的存储和读取。
5.4 JSON
- JSON是一种轻量级的数据交互格式,由于其相对于XML,体积更小,在网络上传输时更加介绍浏览,被广泛用于移动端。大部分APP与服务端的通信都是使用JSON格式进行交互。
6.其他使用
- 6.1 Intent传递数据
- 6.1.1 Serializable 方式
- 相对简单,类及其内部的成员都实现Serializable接口即可,不需要额外的代码,但性能和速度上较慢。
- 查看intent.putExtra()源码可知
- 6.1.1 Serializable 方式
public Intent putExtra(String name, Serializable value) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putSerializable(name, value);
return this;
}
- 传递数据和接收数据代码
传递数据
Book book=new Book();
...
Intent intent=new Intent(this,SecondActivity.class);
intent.putExtra("book",book);
startActivity(intent);
接收数据
Book book= (Book) getIntent().getSerializableExtra("book");
Log.d(TAG,"book title->"+book.getTitle());
Log.d(TAG,"book author name->"+book.getAuthor().getName());
6.1.2 Parcelable 方式
速度较Serializable快10倍以上,但实现起来较复杂,关于Parcelable的使用请参考这篇文章:https://www.jianshu.com/p/82e3090e00e0
6.1.3 将对象转为Json字符串传递,或者将Json转化成对象传递
可以直接参考这篇文章:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0104/2256.html
7.其他介绍
- 7.1 参考链接
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0104/2256.html
https://www.jianshu.com/p/82e3090e00e0
http://www.developerphil.com/parcelable-vs-serializable/
7.2 更新日志
- v1.0.0 2017年3月28日
- v1.1.0 2018年1月29日
7.3 我的博客