Android中Intent中如何传递对象,就我目前所知道的有两种方法,
一种是Bundle.putSerializable(Key,Object);
一种是Bundle.putParcelable(Key, Object);
当然这些Object是有一定的条件的,前者是实现了Serializable接口,而后者是实现了Parcelable接口,
使用:
http://blog.csdn.net/xyz_lmn/article/details/5908355
Activity之间传递数据:
1、Intent直接传
Intent open = new Intent(MainActivity.this,SecondActivity.class);
Person person = new Person();
person.setName("一去二三里");
person.setAge(18);
// 传输方式一,intent直接调用putExtra
// public Intent putExtra(String name, Serializable value)
open.putExtra("put_ser_test", person);
// 传输方式二,intent利用putExtras(注意s)传入bundle
/**
Bundle bundle = new Bundle();
bundle.putSerializable("bundle_ser",person);
open.putExtras(bundle);
*/
startActivity(open);
Intent接收:
Intent intent = getIntent();
// 关键方法:getSerializableExtra ,我们的类是实现了Serializable接口的,所以写这个方法获得对象
// public class Person implements Serializable
Person per = (Person)intent.getSerializableExtra("put_ser_test");
//Person per = (Person)intent.getSerializableExtra("bundle_ser");
mTvDate.setText("名字:"+per.getName()+"\\n"
+"年龄:"+per.getAge());
2、
Parcelable
我们写一个实体类,实现Parcelable接口,马上就被要求
1、复写describeContents方法和writeToParcel方法
2、实例化静态内部对象CREATOR,实现接口Parcelable.Creator 。
也就是,随便一个类实现了Parcelable接口就一开始就会变成这样子
Parcelable方式的实现原理是将一个完整的对象进行分解,而分解后的每一部分都是Intent所支持的数据类型,这样也就实现传递对象的功能了。
四、Serializable 和Parcelable的对比
android上应该尽量采用Parcelable,效率至上
编码上:
Serializable代码量少,写起来方便
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的速度比Serializable 高十倍以上
serializable的迷人之处在于你只需要对某个类以及它的属性实现Serializable 接口即可。Serializable 接口是一种标识接口(marker interface),这意味着无需实现方法,Java便会对这个对象进行高效的序列化操作。
这种方法的缺点是使用了反射,序列化的过程较慢。这种机制会在序列化的时候创建许多的临时对象,容易触发垃圾回收。
Parcelable方式的实现原理是将一个完整的对象进行分解,而分解后的每一部分都是Intent所支持的数据类型,这样也就实现传递对象的功能了
Serializable和Parcelable接口可以完成对象的序列化过程,当我们需要通过Intent和Binder传输数据时就需要使用者两种序列化方式。还有,我们需要对象持久化到存储设备或者通过网络传输给其他客户端,这个使用也需要使用Serializale来完成对象的序列化。在Android应用开发中,这两种方式都很常见,但两者方式并不相同。
1.Serializable接口
Serializable接口是Java提供的一个序列化接口,它是一个空接口,为对象提供标准的序列化和反序列化操作。使用Serializable来实现的对象的序列化相当简单,只需要在类的生命中指定一个类似相面的标识即可自动实现默认的序列化过程。
private static final long serialVersionUID=871238749032;
- 1
完整的对象序列化代码示例如下:
//Model
public class User implements Serializable{
private static final long serialVersionUID=871238749032;
public int userId;
public String userName;
public String password;
}
//序列化到本地
User user=new User(0,"wcl_android@163.com","123456");
ObjectOutputStream out=new ObjectOutputStream(new FileOutputStream("user.obj"));
out.writeObject(user);
out.close;
//反序列化
ObjectInputStream in=new ObjectInputStream(new FileInputStream("user.obj"));
User user=(User)in.readObject();
in.close();
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
这种方式是Java提供的一种序列化方式,过程非常简单,甚至有些开发人员都不需要声明serialVersionUID也可以完成这个过程,但serialVersionUID到底需不需要指定呢?
需要!
Java API既然提供了这个serialVersionUID,那么它必定是有用的。这个serialVersionUID是用来辅助序列化和反序列化过程的,原则上序列化后的数据中的serialVersionUID只有和当前类的serialVersionUID相同才能够正常地被反序列化。
serialVersionUID的详细工作过程是这样的:序列化的时候系统会把当前类的serialVersionUID写入序列化的二进制文件中,当反序列化的时候系统会检测文件中的serialVersionUID是否和当前类的serialVersionUID一致,如果一致就说明序列化的类的版本和当前类的版本是相同的,这个时候可以成功反序列化;否则说明当前类和反序列化的类相比发生了某些变化,比如成员变量的数量、类型发生了变化,这个时候是无法正常反序列化的。
一般来说,我们应该手动指定serialVersionUID的值,比如1L,也可以让IDE根据当前类的结构自动去生成它的hash值,这样序列化和反序列化时两者的serialVersionUID是相同的,因此可以正常进行反序列化操作。如果不手动指定serialVersionUID的值
反序列化时当前类有些改变,比如增加或者删除了某些成员变量,那么系统就会重新计算当前类的hash值并把它赋值给serialVersionUID,这个时候当前类的serialVersionUID就和反序列化数据中的serialVersionUID不一致,就会造成反序列化失败的结果。所以,手动指定serialVersionUID可以在很大程度上避免反序列化过程的失败。
比如当版本升级后,我们可能删除了某个成员变量也可能增加了一些新的成员变量,这个时候我们的反序列化过程依然能够成功,程序仍然能够最大限度地回复数据;相反,如果不指定serialVersionUID的话,程序会发生Crash。
当然,我们还需要考虑一种情况,如果类结构发生了非城规改变,比如修改了类名,修改了成员变量的类型,这个时候尽管serialVersionUID验证通过了,但是反序列化过程仍然会失败,因为类的结构有了毁灭性的改变,根本无法从老版本的数据中还原出一个新的类结构的对象。
对于使用序列化还有两点需要注意:
1.静态成员变量属于类不属于对象,所以不参与序列化过程
2.用transient关键字标记的成员变量不参与序列化过程
2.Parcelable接口
Parcelable接口是Android SDK提供的一种专门用于Android应用中对象的序列化和反序列化的方式,相比于Seriablizable具有更好的性能。实现Parcelable接口的对象就可以实现序列化并可以通过Intent和Binder传递。
下面是一个完成的实现了Parcelable接口的类
public class User implements Parcelable{
public int userId;
public String userName;
public String password;
public Book book;
public User(int userId,String userName,String password,Book book){
this.userId=userId;
this.userName=userName;
this.password=password;
this.book=book;
}
public int describeContents(){
//几乎所有情况都返回0,仅在当前对象中存在文件描述符时返回1
return 0;
}
public void writeToParcel(Parcel out,int flags){
out.writeInt(userId);
out.writeString(userName);
out.writeString(password);
out.writeParcelable(book,0);
}
public static final Parcelable.Creator<User> CREATOR=new Parcelable.Creator<User>(){
public User createFromParcel(Parcel in){
return new User(in);
}
public User[] newArray(int size){
return new User[size];
}
}
private User(Parcel in){
userId=in.readInt();
userName=in.readString();
password=in.readString(); book=in.readParcelable(Thread.currentThread().getContextClassLoader());
}
}
- 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
看起来比Serializable方式复杂太多。我们使用表格把Parcelable方式的相关方法进行说明
方法 | 功能 | 标记位 |
---|---|---|
createFromParcel(Parcel in) | 从序列化后的对象中创建原始对象 | |
newArray(int size) | 创建指定长度的原始对象数组 | |
User(Parcel in) | 从序列化后的对象中创建原始对象 | |
writeToParcel(Parcel out,int flags) | 将当前对象写入序列化结构中 | PARCALABLE_WRITE_RETURN_VALUE |
describeContents | 返回当前对象的内容描述,几乎所有情况都返回0,仅在当前对象中存在文件描述符时返回1 | CONTENTS_FILE_DESCRIPTOR |
既然Parcelable和Serializable都可以实现序列化并且可以用于Intent间的数据传递,那么两者有什么区别呢?
区别 | Serializable | Parcelable |
---|---|---|
所属API | JAVA API | Android SDK API |
原理 | 序列化和反序列化过程需要大量的I/O操作 | 序列化和反序列化过程不需要大量的I/O操作 |
开销 | 开销大 | 开销小 |
效率 | 低 | 很高 |
使用场景 | 序列化到本地或者通过网络传输 | 内存序列化 |