Android 在传递数据时,我们一般使用的是Intent的putExtra()方法来传递数据,但是putExtra()方法所支持的数据类型是有限的,只支持一些常用的数据类型,比如 int,String等。当我们想传递一些自定义的对象的时候,就需要用其他的方式来处理,Android使用Intent来传递对象数据通常有两种实现方式:Serializable 和 Parcelable
本文介绍一下这两种方式的使用方法
Serializable
Serializable是表示将一个对象转换成可存储或可传输的状态,这就是数据的序列化。序列化后的对象可以在网络上进行传输,也可以存储到本地。比如我们定义一个Book类,其中包含bookName和price两个字段,将他序列化只需要让Book类去实现Serializable接口,这样所有的Book对象就是可序列化的了:
public class Book implements Serializable {
private String bookName;
private long price;
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public long getPrice() {
return price;
}
public void setPrice(long price) {
this.price = price;
}
}
在Book类中实现set和get方法,用于对字段数据的赋值和取值,Book类实现了Serializable接口
类之间的数据传递
接下来我们在类中对Book类进行数据的传递,如下:
Book book = new Book();
book.setBookName("java");
book.setPrice((long) 59.0);
Intent intent = new Intent(this,OtherActivity.class);
intent.putExtra("book_data",book);
startActivity(intent);
由于Book实现了Serializable接口,所以在这里我们直接将它传入到putExtra()方法中,通过Intent传递,然后我们在OtherActivity类中获取这个对象,取出我们传递过来的数据。
Intent intent = getIntent();
Book book = (Book) intent.getSerializableExtra("book_data");
Log.i(TAG,"bookName :"+book.getBookName());
Log.i(TAG,"price :"+book.getPrice());
这里我们调用了getSerializableExtra()方法来获取通过参数传递过来的序列化的对象,接着再将它转换成Book对象,这样就实现的自定义对现的数据传递的功能。
将序列化的对象存储到本地
序列化的对象存储到本地,只需要采用ObjectOutputStream和ObjectInputStream即可轻松实现对象的本地存储
代码:
存储本地:
try {
Book book = new Book();
book.setBookName("java");
book.setPrice((long) 59.9);
//序列化的过程
ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(getExternalCacheDir()+"/cache.txt"));
outputStream.writeObject(book);
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
本地取出数据:
try {
//反序列化的过程
ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(getExternalCacheDir()+"/cache.txt"));
Book newBook = (Book) inputStream.readObject();
Log.i("OtherActivity","bookName :"+newBook.getBookName());
Log.i("OtherActivity","price :"+newBook.getPrice());
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
在序列化过程中,我们可以声明一个SerialVersionUID,这个SerialVersionUID也不是必须声明的,这个SerialVersionUID是用来辅助序列化和反序列化过程的,原则上序列化的数据中的SerialVersionUID只有和当前类的SerialVersionUID相同才能够正常的反序列化,SerialVersionUID的详细工作机制是:序列化的时候系统会把当前类的SerialVersionUID写入序列化的文件中,当反序列化的时候系统会去检测文件中的SerialVersionUID,看它是否和当前的类SerialVersionUID一致,如果一致就说明序列化的类的版本和当前类的版本基本相同,这个时候可以成功反序列化,否则就说明当前类和序列化的类相比发生了某些变化,比如成员变量的数量,类型可能发生了变化,这个时候是无法正常反序列化的。所以,我们一般手动指定SerialVersionUID的值,也可以让IDE根据当前类的结构自动生成,这样序列化和反序列化的SerialVersionUID是相同的,就可以正常的进行反序列化。
Parcelable
Parcelable也是一个接口,我们只要实现这个接口,一个类的对象就可以实现序列化并可以通过Intent和Binder传递,我们看下具体的实现方法:
public class Person implements Parcelable {
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;
}
public static final Creator<Person> CREATOR = new Creator<Person>() {
/*从序列化后的对象中创建原始对象*/
@Override
public Person createFromParcel(Parcel in) {
//这个读取数据的顺序一定要和刚才写出的顺序完全相同
Person person = new Person();
person.name = in.readString();//读取name
person.age = in.readInt();//读取age
return person;
}
//创建指定长度的原始对象数组
@Override
public Person[] newArray(int size) {
return new Person[size];
}
};
//返回当前对象的内容描述,含有文件描述符,返回1,否则返回0,几乎所有情况都返回 0
@Override
public int describeContents() {
return 0;
}
/*
* 将当前对象写入序列化结构中,其中flags标识有两种值 0和1
* 为1时表示当前对象需要作为对象返回值返回,不能立即释放资源,几乎所有情况都为0
*/
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);//写出name
dest.writeInt(age);// 写出age
}
}
通过Parcelable序列化的类,我们可以使用相同的代码来传递Person类
Person person = new Person();
person.setName("张三");
person.setAge(20);
Intent intent = new Intent(this,OtherActivity.class);
intent.putExtra("person_data",person);-
startActivity(intent);
获取传过来的值,我们需要使用getParcelableExtra()方法:
Intent intent = getIntent();
Person person = (Person) intent.getParcelableExtra("person_data");
Log.i("OtherActivity","Name :"+person.getName());
Log.i("OtherActivity","age :"+person.getAge());
Serializable和Parcelable对比
Serializable和Parcelable都能实现序列化并且都可用于Intent间的数据传递,他们之间有什么区别呢?
- Serializable是java中的序列化接口,会把整个对象进行序列化,序列化和反序列化需要大量的I/O操作,因此效率会比Parcelable方式低一些。
- Parcelable是Android中的序列化方式,他的效率更高,这是android推荐的序列化方式。Parcelable主要用在内存序列化上,也可以通过Parcelable将对象序列化到存储设备中或者将对象序列化后通过网络传输,但这个过程会稍显复杂,因此推荐在这两种情况下使用serializable。