序列化
MoMo Lv5
  1. 序列化是什么?⭐⭐⭐⭐
  2. 序列化的作用?什么时候需要序列化? ⭐⭐⭐⭐
  3. Android中序列化方式有几种?说说它们的区别。⭐⭐⭐⭐⭐
  4. Bunder传递对象为什么需要序列化?⭐⭐⭐

序列化是什么?序列化的作用?什么时候需要序列化?

字节流便于存储且便于传输,序列化的作用有:

  1. 进行网络传输:将对象或者信息数据转换为字节流格式,特别是Base64格式,并通过网络传输给其他人;
  2. 本地永久性存储:将对象转换为字节流并存放于内存,等到需要用到该对象的时候,再从内存读取字节流并再次构建出该对象;
  3. 进行IPC传输:如需要将某个对象的信息传输给其他的进程,则需要先进行序列化,传输到其他进程后,再将其反序列化构建出原来的对象; 那么,针对将对象转换为字节流的过程称之为“序列化”,而将字节流再次构建为对象的则是“反序列化”。

如何实现序列化

在Android中有两种实现序列化的方式:

Serializable

这是Java自带的序列化方法,可以通过实现Serializable接口来实现序列化。序列化后的对象可以进行网络传输,也可以存储到本地磁盘。然而这个方式并不推荐,因为其内部实现原理是通过Java的反射机制 ,该机制效率相对低,同时会产生很多临时对象,因此就需要频繁地进行垃圾回收;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//构建一个实现了Serializable接口的类
public class XrData implements Serializable {
public String name;
public String phone;
}

//序列化
public static MyFragment newInstance(XrData entity) {
MyFragment fragment = new MyFragment();
Bundle bundle = new Bundle();
bundle.putSerializable("DATA", entity); //1
fragment.setArguments(bundle);
return fragment;
}
//反序列化
private void setData(){
mContact = (XrData) getArguments().getSerializable("DATA"); //2
if(mContact != null) {
contact_name.setText(mContact.name);
contact_phone.setText(mContact.phone);
}
}

上面注释1就是将entity变量进行序列化,转换为字节流后存放在Bundle里(Bundle主要用于传递数据,它保存的数据,是以key-value(键值对)的形式存在的)。在注释2,再次通过反序列化构建出原来的对象。

Parcelable

使用方法

这是安卓专用的序列化方式。Parcelable接口比Serializable接口效率更高,性能方面要高出10多倍。因为其实现原理是把对象分解为Intent支持的数据类型,并通过Intent进行传输,其数据可以保存在内存中,相对于Serializable将数据保存在磁盘,效率自然更高。Parcelable的用法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
// CutInfo.java 定义一个CutInfo类
public class CutInfo implements Parcelable {
/**
* 裁剪比例
*/
private int offsetX;
/**
* 裁剪比例
*/
private int offsetY;


public CutInfo() {
}

public int getOffsetX() {
return offsetX;
}

public void setOffsetX(int offsetX) {
this.offsetX = offsetX;
}

public int getOffsetY() {
return offsetY;
}

public void setOffsetY(int offsetY) {
this.offsetY = offsetY;
}

// 序列化
@Override
public void writeToParcel(Parcel dest, int flags) { //3
dest.writeInt(this.offsetX);
dest.writeInt(this.offsetY);
}

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

// 反序列化
protected CutInfo(Parcel in) {
this.offsetX = in.readInt();
this.offsetY = in.readInt();
}

// 反序列化
public static final Creator<CutInfo> CREATOR = new Creator<CutInfo>() { //5
@Override
public CutInfo createFromParcel(Parcel source) {
return new CutInfo(source);
}

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

// ActivityA.java 实现序列化
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(this, ActivityB.class);
intent.putExtra("cut", new CutInfo(8, 8));
startActivity(intent);
}
});

// ActivityB.java 获取并反序列化
Intent intent = getIntent();
CutInfo cut = intent.getParcelableExtra("cut");
Log.d("ActivityB", cut.toString()); //会输出: “8, 8”

Parcelable解析

了解Parcelable就要先了解什么是Parcel,即[注释3]的Parcel。Parcel翻译过来就是“打包”的意思。通过Parcel可以讲序列化后的数据写入一片共享内存中,其他进程再通过Parcel从共享内存读取数据,并反序列化得到目标对象。

接着,一个类要实现Parcelable接口,需要实现以下两个接口:

  • describeContents:负责文件描述,只针对一些特殊的需要描述信息的对象,需要返回1,其他情况返回0即可,对应[注释4]
  • writeToParcel:通过writeToParcel方法实现序列化。

反序列化需要定义一个CREATOR的变量,通过匿名内部类实现Parcelable中的Creator的接口。对应[注释5]

Bunder传递对象为什么需要序列化?

因为bundle传递数据时只支持基本数据类型,所以在传递对象时,需要先将对象进行序列化,转换成可存储或可传输的字节流。

Android为什么引入Parcelable?Serialzable和Parcelable的区别?

  • Serialzable序列后的数据存在磁盘上,Parcelable则是直接在内存中读写,因此效率更高;
  • Serialzable是Java自带的序列化方法,使用Java的反射机制,效率相对低,且会产生大量临时对象,导致频繁进行垃圾回收;Parcelable 是自己实现封送和解封,通过将对象分解为Intent所支持的数据类型进行传输。
  • Parcelable相比较Serializable要复杂的很多,Serializable序列化只要对象继承该接口,即可。但是Parcelable则需要实现writeToParcel、describeContents函数以及静态的CREATOR变量,实际上就是将如何打包和解包的工作自己来定义,而序列化的这些操作完全由底层实现。
Powered by Hexo & Theme Keep
Unique Visitor Page View