老司机开车带你体验Parcelable到底有多快

Parcelable和Serializable都是序列化反序列化的解决方案,众所周知,前者的效率和内存占用相对后者都是有优势的,那么,Parcelable到底比Serializable快多少呢,老司机写个Demo带你来测试一把。

在测试之前我说一下我的思路:
在一个Activity中从把Serializable或者Parcelable对象放入Bundle中开始计时,到带到另一个Activity中在OnCreate中从Bundle中取出Serializable或Parcelable对象时停止,记为一次测试时长,当然,这个时长是有杂质存在的,即它还包含了Activity之间做跳转等一系列内容,这里称之为杂质,我们需要剔除。

杂质的计算方式很简单,把上述的步骤中去除开始的Activity将数据加入Bundle的代码和在跳转到的Activity的OnCreate中从Bundle取出数据的代码,这段时间就是我们的杂质时间。

故(测试Serializable的去除杂质的时间)/(测试Parcelable的去除杂质的时间)=我们要的效率值

这样得出来的结果就能看出说明在从一个Activity传内容基本一致的数据到另一个Activity时使用Parcelable的对象比使用Serializable对象要快多少。

当然,仅仅一次测试是不能说明问题的,各种测试的值都是浮动的,所以我们需要加大这种测试的数据,将这些测试做个几千次甚至上万次然后再取平均值,就能得到一个比较准确的结论了(不懂的人想想抛一万次硬币是不是正反面的概率都在0.5左右)

具体内容看代码

首先来两个相似的类,内容都差不多

这个类是实现了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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
public class JonSnow implements Parcelable {
private String name;
private int age;
private List<FuckedWhore> fuckedWhoreList;

public JonSnow() {
}

public JonSnow(Parcel source) {
this.name = source.readString();
this.age = source.readInt();
this.fuckedWhoreList = new ArrayList<FuckedWhore>();
source.readTypedList(fuckedWhoreList,FuckedWhore.CREATOR);
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public List<FuckedWhore> getFuckedWhoreList() {
return fuckedWhoreList;
}

public void setFuckedWhoreList(List<FuckedWhore> fuckedWhoreList) {
this.fuckedWhoreList = fuckedWhoreList;
}

public String getName() {
return name;
}

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

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

@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeInt(age);
dest.writeTypedList(fuckedWhoreList);
}

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

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



public static class FuckedWhore implements Parcelable{
private String name;
private int age;

public FuckedWhore(){

}

public FuckedWhore(Parcel source) {
this.name = source.readString();
this.age = source.readInt();
}

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

@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeInt(age);
}
static final Parcelable.Creator<FuckedWhore> CREATOR = new Creator<FuckedWhore>() {
@Override
public FuckedWhore createFromParcel(Parcel source) {
return new FuckedWhore(source);
}

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

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public String getName() {
return name;
}

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

}

这个是实现了Serializable接口的类

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
public class IMP implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int age;
private List<FuckedWhore> fuckedWhoreList;

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public List<FuckedWhore> getFuckedWhoreList() {
return fuckedWhoreList;
}

public void setFuckedWhoreList(List<FuckedWhore> fuckedWhoreList) {
this.fuckedWhoreList = fuckedWhoreList;
}

public String getName() {
return name;
}

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

public static class FuckedWhore implements Serializable{
private static final long serialVersionUID = 1L;
private String name;
private int age;

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public String getName() {
return name;
}

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

然后写两个Activity,一个是跳转前提供Bundle的,另一个是跳转后解析Bundle的
跳转前的TestParcelableActivity

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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
public class TestParcelableActivity extends Activity {
@BindView(R.id.tvParcelable)
TextView tvParcelable;
@BindView(R.id.tvResultP)
TextView tvResultP;
@BindView(R.id.tvSerializable)
TextView tvSerializable;
@BindView(R.id.tvResultS)
TextView tvResultS;
@BindView(R.id.tvTest)
TextView tvTest;
@BindView(R.id.tvResult)
TextView tvResult;

private JonSnow jonSnow;
private IMP imp;
private long totalTestTime;

private long perParcelabel;
private long perSerializable;
private long perEmpty;


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test_parcelabel);
ButterKnife.bind(this);
initIMP();
initJsonSnow();
}

@OnClick(R.id.tvTest)
public void startTest(){
totalTestTime = 0;
perParcelabel = 0;
perSerializable = 0;
perEmpty = 0;
testEmpty();
}

private void testEmpty(){
Constant.MODE = 0;
Bundle bundle = new Bundle();
Constant.start = System.currentTimeMillis();
for(long i = 0;i<Constant.TEST_TIME;i++){

}
Intent intent = new Intent(TestParcelableActivity.this, TestResultActivity.class);
intent.putExtras(bundle);
startActivityForResult(intent, Constant.REQ_CDOE);
}

@OnClick(R.id.tvParcelable)
public void testParcelabel(){
Constant.MODE = 1;
Bundle bundle = new Bundle();
Constant.start = System.currentTimeMillis();
for(long i = 0;i<Constant.TEST_TIME;i++){
bundle.putParcelable("parcelable" + i, jonSnow);
}
Intent intent = new Intent(TestParcelableActivity.this, TestResultActivity.class);
intent.putExtras(bundle);
startActivityForResult(intent, Constant.REQ_CDOE);
}

@OnClick(R.id.tvSerializable)
public void testSerializable(){
Constant.MODE = 2;
Bundle bundle = new Bundle();
Constant.start = System.currentTimeMillis();
for(long i = 0;i<Constant.TEST_TIME;i++){
bundle.putSerializable("Serializable" + i, imp);
}
Intent intent = new Intent(TestParcelableActivity.this, TestResultActivity.class);
intent.putExtras(bundle);
startActivityForResult(intent, Constant.REQ_CDOE);
}

private void initJsonSnow(){
jonSnow = new JonSnow();
jonSnow.setName("Json Snow");
jonSnow.setAge(25);
List<JonSnow.FuckedWhore> whoreList = new ArrayList<JonSnow.FuckedWhore>();
for(int i = 0;i<Constant.TEST_MOUNT;i++){
JonSnow.FuckedWhore whore = new JonSnow.FuckedWhore();
whore.setName("a girl");
whore.setAge(15);
whoreList.add(whore);
}
jonSnow.setFuckedWhoreList(whoreList);
}

private void initIMP(){
imp = new IMP();
imp.setName("Tyrion Lannister");
imp.setAge(30);
List<IMP.FuckedWhore> whoreList = new ArrayList<IMP.FuckedWhore>();
for(int i = 0;i<Constant.TEST_MOUNT;i++){
IMP.FuckedWhore whore = new IMP.FuckedWhore();
whore.setName("Shae");
whore.setAge(14);
whoreList.add(whore);
}
imp.setFuckedWhoreList(whoreList);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == RESULT_OK){
totalTestTime++;
if(totalTestTime<Constant.TEST_CYCLE){
switch (Constant.MODE){
case 0:
testEmpty();
break;
case 1:
testParcelabel();
break;
case 2:
testSerializable();
break;

}
}else {
switch (Constant.MODE){
case 0:
resultEmpty();
break;
case 1:
resultParcelable();
break;
case 2:
resultSerializable();
break;

}

}

}

}

private void resultEmpty(){
perEmpty = Constant.perTime();
totalTestTime = 0;
tvResult.setText("Empty :"+perEmpty);
testParcelabel();
}

private void resultParcelable(){
perParcelabel = Constant.perTime();
totalTestTime = 0;
tvResultP.setText("parcelable:"+perParcelabel);
testSerializable();
}

private void resultSerializable(){
perSerializable = Constant.perTime();
totalTestTime = 0;
tvResultS.setText("serializable"+perSerializable);
float result = (perSerializable-perEmpty)/(perParcelabel-perEmpty);
tvResult.setText("Result:"+result);
}

}

这个是解析Bundle的TestResultActivity

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
public class TestResultActivity extends Activity {
private Bundle bundle;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bundle = getIntent().getExtras();
switch (Constant.MODE){
case 0:
testEmpty();
break;
case 1:
testParcelable();
break;
case 2:
testSerializable();
break;

}
Constant.result();
setResult(RESULT_OK);
finish();
}

private void testEmpty(){
Constant.end = System.currentTimeMillis();
}

private void testParcelable(){
JonSnow jonSnow;
for(int i = 0;i<Constant.TEST_TIME;i++){
jonSnow = bundle.getParcelable("parcelable" + i);
}
Constant.end = System.currentTimeMillis();
}

private void testSerializable(){
IMP imp;
for(int i = 0;i<Constant.TEST_TIME;i++){
imp = (IMP) bundle.getSerializable("Serializable" + i);
}
Constant.end = System.currentTimeMillis();
}
}

为了减少其他部分对测试结果的影响,把一些公用的变量放在常量里了(没事别干这种事)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Constant {
public static long start;
public static long end;
public static long tempResult;
public static long result;
public static int MODE = 0;//mode = 0 empty 1 perParcelable 2Serializable
public static final long TEST_TIME = 10;
public static final long TEST_CYCLE = 500;
public static final long TEST_MOUNT = 1000;

public static final int REQ_CDOE = 0x01;

public static long result (){
tempResult = tempResult + end-start;
return tempResult;
}

public static long perTime(){
result = tempResult/TEST_CYCLE;
tempResult = 0;
return result;
}
}


最后运行一下看看结果:Parcelable比Serializable快了3倍左右,当然,误差是存在的,但是大量实验结果都在3倍左右浮动,说明在从一个Activity传数据到另一个Activity时使用Parcelable的对象比使用Serializable对象要快3倍左右。so…你懂的

当然,除了在速度方面,内存占用上Parcelable也是占优势的,因为Serializable用到了反射,在序列化和反序列化的过程中会造一大堆临时变量,可能造成频繁GC哟,对机器的代价还是要高许多的,特别是当我们数据量比较大的情况下,可能就会有很明显的感觉了,影响用户体验就不好咯

最后的结论是,同志们,如果你现在还在用两个轮子的交通工具,时间较为充裕的情况下,是时候换成四个轮子的东东了。

Maydaaa wechat
欢迎添加微信好友共同交流学习!
坚持原创技术分享,您的支持将鼓励我继续创作!