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接口的(不要在意命名,最近权利的游戏看多了。。。。)
public class JonSnow implements Parcelable {
private String name;
private int age;
private List fuckedWhoreList;
public JonSnow() {
}
public JonSnow(Parcel source) {
this.name = source.readString();
this.age = source.readInt();
this.fuckedWhoreList = new ArrayList();
source.readTypedList(fuckedWhoreList,FuckedWhore.CREATOR);
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public List getFuckedWhoreList() {
return fuckedWhoreList;
}
public void setFuckedWhoreList(List 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 CREATOR = new Creator() {
@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 CREATOR = new Creator() {
@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接口的类
public class IMP implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int age;
private List fuckedWhoreList;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public List getFuckedWhoreList() {
return fuckedWhoreList;
}
public void setFuckedWhoreList(List 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
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
}
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
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
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 whoreList = new ArrayList();
for(int i = 0;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 whoreList = new ArrayList();
for(int i = 0;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
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
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
jonSnow = bundle.getParcelable("parcelable" + i);
}
Constant.end = System.currentTimeMillis();
}
private void testSerializable(){
IMP imp;
for(int i = 0;i
imp = (IMP) bundle.getSerializable("Serializable" + i);
}
Constant.end = System.currentTimeMillis();
}
}
为了减少其他部分对测试结果的影响,把一些公用的变量放在常量里了(没事别干这种事)
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哟,对机器的代价还是要高许多的,特别是当我们数据量比较大的情况下,可能就会有很明显的感觉了,影响用户体验就不好咯
最后的结论是,同志们,如果你现在还在用两个轮子的交通工具,时间较为充裕的情况下,是时候换成四个轮子的东东了。