一.先从Serialize说起
我们都知道JAVA中的Serialize机制,译成串行化、序列化……,其作用是能将数据对象存入字节流当中,在需要时重新生成对象。主要应用是利用外部存储设备保存对象状态,以及通过网络传输对象等。
二、Android中的新的序列化机制
在Android系统中,定位为针对内存受限的设备,因此对性能要求更高,另外系统中采用了新的IPC(进程间通信)机制,必然要求使用性能更出色的对象传输方式。在这样的环境下,Parcel被设计出来,其定位就是轻量级的高效的对象序列化和反序列化机制。
三、Android中的Serialable和Parcelable的区别
1、作用
Serializable的作用是为了保存对象的属性到本地文件、数据库、网络流、rmi以方便数据传输,当然这种传输可以是程序内的也可以是两个程序间的。而Android的Parcelable的设计初衷是因为Serializable效率过慢,为了在程序内不同组件间以及不同Android程序间(AIDL)高效的传输数据而设计,这些数据仅在内存中存在,Parcelable是通过IBinder通信的消息的载体。
从上面的设计上我们就可以看出优劣了。
2、效率及选择
Parcelable的性能比Serializable好,在内存开销方面较小,所以在内存间数据传输时推荐使用Parcelable,如activity间传输数据,而Serializable可将数据持久化方便保存,所以在需要保存或网络传输数据时选择Serializable,因为android不同版本Parcelable可能不同,所以不推荐使用Parcelable进行数据持久化
3、编程实现
对于Serializable,类只需要实现Serializable接口,并提供一个序列化版本id(serialVersionUID)即可。而Parcelable则需要实现writeToParcel、describeContents函数以及静态的CREATOR变量,实际上就是将如何打包和解包的工作自己来定义,而序列化的这些操作完全由底层实现。
Parcelable的一个实现例子如下
1. publicclass MyParcelable implements
2. privateint mData;
3. private
4.
5. publicint describeContents() {
6. return 0;
7. }
8.
9. // 写数据进行保存
10. publicvoid writeToParcel(Parcel out, int
11. out.writeInt(mData);
12. out.writeString(mStr);
13. }
14.
15. // 用来创建自定义的Parcelable的对象
16. publicstatic final
17. = new
18. public
19. return new
20. }
21.
22. public MyParcelable[] newArray(int
23. return new
24. }
25. };
26.
27. // 读数据进行恢复
28. private
29. mData = in.readInt();
30. mStr = in.readString();
31. }
32. }
publicclass MyParcelable implements Parcelable {
privateint mData;
private String mStr;
publicint describeContents() {
return 0;
}
// 写数据进行保存
publicvoid writeToParcel(Parcel out, int flags) {
out.writeInt(mData);
out.writeString(mStr);
}
// 用来创建自定义的Parcelable的对象
publicstatic final Parcelable.Creator<MyParcelable> CREATOR
= new Parcelable.Creator<MyParcelable>() {
public MyParcelable createFromParcel(Parcel in) {
return new MyParcelable(in);
}
public MyParcelable[] newArray(int size) {
return new MyParcelable[size];
}
};
// 读数据进行恢复
private MyParcelable(Parcel in) {
mData = in.readInt();
mStr = in.readString();
}
}
从上面我们可以看出Parcel的写入和读出顺序是一致的。如果元素是list读出时需要先new一个ArrayList传入,否则会报空指针异常。如下:
list= new
in.readStringList(list);
PS: 在自己使用时,read数据时误将前面int数据当作long读出,结果后面的顺序错乱,报如下异常,当类字段较多时务必保持写入和读取的类型及顺序一致。
11-2120:14:10.317: E/AndroidRuntime(21114): Caused by: java.lang.RuntimeException:Parcel android.os.Parcel@4126ed60: Unmarshalling unknown type code 3014773 atoffset 164
4、高级功能上
Serializable序列化不保存静态变量,可以使用Transient关键字对部分字段不进行序列化,也可以覆盖writeObject、readObject方法以实现序列化过程自定义
四、Parcelable应用
Parcelable是在内存中完成的序列化和反序列化,利用的是连续的内存空间,因此会更加高效。
我们接下来要说的是Parcel类如何应用。就应用程序而言,最常见使用Parcel类的场景就是在Activity间传递数据。没错,在Activity间使用Intent传递数据的时候,可以通过Parcelable机制传递复杂的对象。
下面来看一下简单的代码:
UserInfo类,实现了Parcelable接口:
1. package
2.
3. import
4. import
5.
6. import
7. import
8.
9. /**
10. * 用户信息,实现Parcelable接口
11. * String,int,String[],ArrayList<HashMap<String,Object>>这四种类型测试
12. * @author weijiang204321
13. *
14. */
15. public class UserInfo implements
16.
17. private
18. private
19. private int
20. private String[] boyfriendAry = new String[3];
21. private ArrayList<HashMap<String,SonInfo>> listData = new
22. private
23.
24. public
25. }
26.
27. public UserInfo(String id,String name,int
28. this.id = id;
29. this.name = name;
30. this.age = age;
31. this.boyfriendAry = boyfriendAry;
32. this.listData = listData;
33. }
34.
35. public
36. id = source.readString();
37. name = source.readString();
38. age = source.readInt();
39. sonInfo = source.readParcelable(SonInfo.class.getClassLoader());
40. source.readStringArray(boyfriendAry);
41. source.readList(listData, SonInfo.class.getClassLoader());
42. }
43.
44. public
45. return
46. }
47.
48. public void
49. this.id = id;
50. }
51.
52. public
53. return
54. }
55.
56. public void
57. this.name = name;
58. }
59.
60. public int
61. return
62. }
63.
64. public void setAge(int
65. this.age = age;
66. }
67.
68. public
69. return
70. }
71.
72. public void
73. this.sonInfo = sonInfo;
74. }
75.
76. public
77. return
78. }
79.
80. public void
81. this.boyfriendAry = boyfriendAry;
82. }
83.
84. public
85. return
86. }
87.
88. public void
89. this.listData = listData;
90. }
91.
92.
93. @Override
94. public int
95. return 0;
96. }
97.
98. //进行序列化存储
99. @Override
100. public void writeToParcel(Parcel dest, int
101. dest.writeString(id);
102. dest.writeString(name);
103. dest.writeInt(age);
104. dest.writeParcelable(sonInfo, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
105.
106. dest.writeStringArray(boyfriendAry);
107. dest.writeList(listData);
108. }
109.
110. public static final Parcelable.Creator<UserInfo> CREATOR = new
111. @Override
112. public UserInfo[] newArray(int
113. return new
114. }
115.
116. //将Parcel对象反序列化为UserInfo
117. @Override
118. public
119. return new
120. }
121. };
122.
123. }
package com.demo.entity;
import java.util.ArrayList;
import java.util.HashMap;
import android.os.Parcel;
import android.os.Parcelable;
/**
* 用户信息,实现Parcelable接口
* String,int,String[],ArrayList<HashMap<String,Object>>这四种类型测试
* @author weijiang204321
*
*/
public class UserInfo implements Parcelable{
private String id;
private String name;
private int age;
private String[] boyfriendAry = new String[3];
private ArrayList<HashMap<String,SonInfo>> listData = new ArrayList<HashMap<String,SonInfo>>();
private SonInfo sonInfo;
public UserInfo(){
}
public UserInfo(String id,String name,int age,String[] boyfriendAry,ArrayList<HashMap<String,SonInfo>> listData){
this.id = id;
this.name = name;
this.age = age;
this.boyfriendAry = boyfriendAry;
this.listData = listData;
}
public UserInfo(Parcel source){
id = source.readString();
name = source.readString();
age = source.readInt();
sonInfo = source.readParcelable(SonInfo.class.getClassLoader());
source.readStringArray(boyfriendAry);
source.readList(listData, SonInfo.class.getClassLoader());
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
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;
}
public SonInfo getSonInfo(){
return sonInfo;
}
public void setSonInfo(SonInfo sonInfo){
this.sonInfo = sonInfo;
}
public String[] getBoyfriendAry() {
return boyfriendAry;
}
public void setBoyfriendAry(String[] boyfriendAry) {
this.boyfriendAry = boyfriendAry;
}
public ArrayList<HashMap<String, SonInfo>> getListData() {
return listData;
}
public void setListData(ArrayList<HashMap<String, SonInfo>> listData) {
this.listData = listData;
}
@Override
public int describeContents() {
return 0;
}
//进行序列化存储
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(id);
dest.writeString(name);
dest.writeInt(age);
dest.writeParcelable(sonInfo, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
dest.writeStringArray(boyfriendAry);
dest.writeList(listData);
}
public static final Parcelable.Creator<UserInfo> CREATOR = new Creator<UserInfo>() {
@Override
public UserInfo[] newArray(int size) {
return new UserInfo[size];
}
//将Parcel对象反序列化为UserInfo
@Override
public UserInfo createFromParcel(Parcel source) {
return new UserInfo(source);
}
};
}
同样SonInfo类也要实现Parcelable接口:
1. package
2.
3. import
4. import
5.
6. public class SonInfo implements
7.
8. private
9. private
10.
11. public
12.
13. }
14.
15. public
16. this.id = id;
17. this.name = name;
18. }
19.
20. public
21. this.id = source.readString();
22. this.name = source.readString();
23. }
24.
25. public
26. return
27. }
28. public void
29. this.id = id;
30. }
31. public
32. return
33. }
34. public void
35. this.name = name;
36. }
37.
38. @Override
39. public int
40. return 0;
41. }
42.
43. @Override
44. public void writeToParcel(Parcel dest, int
45. dest.writeString(id);
46. dest.writeString(name);
47. }
48.
49. public static final Parcelable.Creator<SonInfo> CREATOR = new
50. @Override
51. public SonInfo[] newArray(int
52. return new
53. }
54.
55. //将Parcel对象反序列化为UserInfo
56. @Override
57. public
58. return new
59. }
60. };
61.
62. }
package com.demo.entity;
import android.os.Parcel;
import android.os.Parcelable;
public class SonInfo implements Parcelable{
private String id;
private String name;
public SonInfo(){
}
public SonInfo(String id,String name){
this.id = id;
this.name = name;
}
public SonInfo(Parcel source){
this.id = source.readString();
this.name = source.readString();
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
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(id);
dest.writeString(name);
}
public static final Parcelable.Creator<SonInfo> CREATOR = new Creator<SonInfo>() {
@Override
public SonInfo[] newArray(int size) {
return new SonInfo[size];
}
//将Parcel对象反序列化为UserInfo
@Override
public SonInfo createFromParcel(Parcel source) {
return new SonInfo(source);
}
};
}
下面来看一下测试类:
MainActivity类,在这里面进行数据的封装,然后传递到StubActivity类中:
1. package
2.
3. import
4. import
5.
6. import
7. import
8. import
9.
10. import
11. import
12.
13. public class MainActivity extends
14.
15. @Override
16. protected void
17. super.onCreate(savedInstanceState);
18. setContentView(R.layout.activity_main);
19.
20. Intent intent = new Intent(this,StubActivity.class);
21. ArrayList<HashMap<String,SonInfo>> listData = new
22. HashMap<String,SonInfo> tempMap = new
23. tempMap.put("one_child", new SonInfo("001_1","jiangwei_one_child"));
24. listData.add(tempMap);
25.
26. UserInfo userInfo = new UserInfo("001","jiangwei",24,new String[]{"张三","李四","王五"},listData);
27. SonInfo sonInfo = new
28. sonInfo.setId("001_1");
29. sonInfo.setName("jiangwei_child");
30. userInfo.setSonInfo(sonInfo);
31. intent.putExtra("userinfo", userInfo);
32. startActivity(intent);
33.
34. }
35.
36. }
package com.demo.parcel;
import java.util.ArrayList;
import java.util.HashMap;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import com.demo.entity.SonInfo;
import com.demo.entity.UserInfo;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this,StubActivity.class);
ArrayList<HashMap<String,SonInfo>> listData = new ArrayList<HashMap<String,SonInfo>>();
HashMap<String,SonInfo> tempMap = new HashMap<String,SonInfo>();
tempMap.put("one_child", new SonInfo("001_1","jiangwei_one_child"));
listData.add(tempMap);
UserInfo userInfo = new UserInfo("001","jiangwei",24,new String[]{"张三","李四","王五"},listData);
SonInfo sonInfo = new SonInfo();
sonInfo.setId("001_1");
sonInfo.setName("jiangwei_child");
userInfo.setSonInfo(sonInfo);
intent.putExtra("userinfo", userInfo);
startActivity(intent);
}
}
下面就是StubActivity类,在这个类中将读出数据进行显示:
1. package
2.
3. import
4. import
5.
6. import
7. import
8. import
9.
10. import
11. import
12.
13. public class StubActivity extends
14.
15. @Override
16. protected void
17. super.onCreate(savedInstanceState);
18. setContentView(R.layout.activity_stub);
19.
20. UserInfo userInfo = (UserInfo)this.getIntent().getParcelableExtra("userinfo");
21. SonInfo sonInfo = userInfo.getSonInfo();
22.
23. String[] boyfriend = userInfo.getBoyfriendAry();
24. for(int i=0;i<boyfriend.length;i++){
25. Log.e("boyfriend_name:",boyfriend[i]);
26. }
27.
28. ArrayList<HashMap<String,SonInfo>> listData = userInfo.getListData();
29. for(int j=0;j<listData.size();j++){
30. SonInfo temp_soninfo = listData.get(j).get("one_child");
31. Log.e("OneChildId:",temp_soninfo.getId()+"");
32. Log.e("OneChildName:",temp_soninfo.getName()+"");
33. }
34.
35.
36.
37. Log.e("UserId:",userInfo.getId()+"");
38. Log.e("UserName:",userInfo.getName()+"");
39. Log.e("UserAge:",userInfo.getAge()+"");
40. Log.e("Son_id:",sonInfo.getId()+"");
41. Log.e("Son_name:",sonInfo.getName()+"");
42.
43. }
44.
45. }
package com.demo.parcel;
import java.util.ArrayList;
import java.util.HashMap;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import com.demo.entity.SonInfo;
import com.demo.entity.UserInfo;
public class StubActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_stub);
UserInfo userInfo = (UserInfo)this.getIntent().getParcelableExtra("userinfo");
SonInfo sonInfo = userInfo.getSonInfo();
String[] boyfriend = userInfo.getBoyfriendAry();
for(int i=0;i<boyfriend.length;i++){
Log.e("boyfriend_name:",boyfriend[i]);
}
ArrayList<HashMap<String,SonInfo>> listData = userInfo.getListData();
for(int j=0;j<listData.size();j++){
SonInfo temp_soninfo = listData.get(j).get("one_child");
Log.e("OneChildId:",temp_soninfo.getId()+"");
Log.e("OneChildName:",temp_soninfo.getName()+"");
}
Log.e("UserId:",userInfo.getId()+"");
Log.e("UserName:",userInfo.getName()+"");
Log.e("UserAge:",userInfo.getAge()+"");
Log.e("Son_id:",sonInfo.getId()+"");
Log.e("Son_name:",sonInfo.getName()+"");
}
}
运行结果:
这样就成功了使用了Parcelable进行数据的传输。