1.序列化
1.1 序列化的定义
序列化 (Serialization)将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。简单地说,“序列化”就是将运行时的对象状态转换成二进制,然后保存到流、内存或者通过网络传输给其他端。
1.2 序列化的使用场景
我们通过Intent传递数据,官方给我们提供了许多的接口,我们可以传递整型,浮点,字符串类型等等,但是我们要传递复杂类型的就不行了,这个时候需要将复杂类型进行序列化
1.3 序列化的方式
- 实现Serializable接口(Java);
- 实现Parcelable接口(Android)。
1.4 如何选择序列化方式
1)在使用内存的时候,Parcelable比Serializable性能高,所以推荐使用Parcelable。
2)Serializable在序列化和反序列化频繁进行 I/O操作,非常占用内存,在序列化的时候创建许多的临时对象,容易触发垃圾回收,另外使用了反射,序列化的过程较慢。
3)Parcelable不能使用在要将数据存储在磁盘上的情况,因为Parcelable不能很好的保证数据的持续性在外界有变化的情况下。尽管Serializable效率低点,但此时还是建议使用Serializable 。
2.Serializable 接口
Serializable是序列化的意思,表示将一个对象转换成可存储或可传输的状态。序列化后的对象可以在网络或组件上进行传输,也可以存储到本地。
Serializable 是 Java 提供的序列化接口,它是一个空接口:
public interface Serializable {
}
Serilizable序列化很多工作系统都帮我们完成了,我们只需要实现Serializable接口。
2.1 关于Serializable接口
可序列化类中,未实现 Serializable 的属性状态无法被序列化/反序列化也就是说,反序列化一个类的过程中,它的非可序列化的属性将会调用无参构造函数重新创建, 因此这个属性的无参构造函数必须可以访问,否者运行时会报错。
一个实现序列化的类,它的子类也是可序列化的;
Serializable有个唯一标识符serialVersionUID,这个serialVersionUID可以我们自己定义,也可以由系统生成,这个标识符是用来确认序列化和反序列化是不是同一个对象,是同一个对象反序列化成功,但是如果当前类有所改变,比如增加或者删除了成员变量,那么系统会重新计算当前类的hash值,赋值给serialVersionUID,发现前后不一样,序列化失败。
serialVersionUID生成方法:
1.Settings->Editor->Inspections->勾选serialVersionUID。
2.当实现Serializable接口,程序会报警告,用快捷键(我的是ALT+Enter)生成serialVersionUID.
2.2 Serilizable的实际应用
我们就以在组件Activity传递对象为例;
如何在组件中传递对象,只需要将类实现Serializable接口。
1.新建一个实体类实现Serializable接口;
**
* Created by zhangcong on 2017/11/15.
* @author zhangcong
*/
public class User implements Serializable{
private static final long serialVersionUID = 8066301618436107542L;
private String name;
private String password;
public User(String name, String password) {
this.name = name;
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
2.在MainActivity序列化;
public class MainActivity extends AppCompatActivity {
private Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button =findViewById(R.id.bt_click);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
User user=new User("Simon","222222");
Intent intent=new Intent(MainActivity.this, SerializableActivity.class);
intent.putExtra("Simon",user);
startActivity(intent);
}
});
}
}
3.在目标activity取出序列化的对象:
public class SerializableActivity extends Activity{
private TextView textView;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_common);
textView=findViewById(R.id.tv_text);
Intent intent=getIntent();
User user= (User) intent.getSerializableExtra("Simon");
textView.setText(user.getName()+ " "+ user.getPassword());
}
}
3.Parcelable接口
Parcelable 是 Android 特有的序列化接口。
3.1 关于Parcelable接口
Parcelable使用时要用到一个Parcel,可以简单将其看为一个容器,序列化时将数据写入Parcel,反序列化时从中取出。
Parcelable源码:
public interface Parcelable {
int CONTENTS_FILE_DESCRIPTOR = 1;
int PARCELABLE_WRITE_RETURN_VALUE = 1;
//描述当前 Parcelable 实例的对象类型
//比如说,如果对象中有文件描述符,这个方法就会返回上面的 CONTENTS_FILE_DESCRIPTOR
//其他情况会返回一个位掩码
int describeContents();
//将对象转换成一个 Parcel 对象
//参数中 var1表示要写入的 Parcel 对象
//var2表示这个对象将如何写入
void writeToParcel(Parcel var1, int var2);
//对象创建时提供的一个创建器
public interface ClassLoaderCreator<T> extends Parcelable.Creator<T> {
//使用类加载器和之前序列化成的 Parcel 对象反序列化一个对象
T createFromParcel(Parcel var1, ClassLoader var2);
}
//实现类必须有一个 Creator 属性,用于反序列化,将 Parcel 对象转换为 Parcelable
public interface Creator<T> {
T createFromParcel(Parcel var1);
T[] newArray(int var1);
}
}
Parcelable就是通过writeToParcel()方法进行序列化的。序列化的时候讲数据写入Parcel。想要知道Parcelable的原理,就必须弄清楚Parcel是什么?
3.2 Parcel简介:
Parcel翻译过来是打包的意思,其实就是包装了我们需要传输的数据,然后在Binder中传输,也就是用于跨进程传输数据
简单来说,Parcel提供了一套机制,可以将序列化之后的数据写入到一个共享内存中,其他进程通过Parcel可以从这块共享内存中读出字节流,并反序列化成对象,下图是这个过程的模型。
Parcel可以包含原始数据类型(用各种对应的方法写入,比如writeInt(),writeFloat()等),可以包含Parcelable对象,它还包含了一个活动的IBinder对象的引用,这个引用导致另一端接收到一个指向这个IBinder的代理IBinder。Parcelable通过Parcel实现了read和write的方法,从而实现序列化和反序列化。
3.3 Parcelable接口使用实例
1.将实体类实现Parcelable接口,我们需要重写几个方法;
/**
*
* @author zhangcong
* @date 2017/11/16
*/
public class Person implements Parcelable {
private String name;
private int age;
// 系统自动添加,给createFromParcel里面用
protected Person(Parcel in) {
name=in.readString();
age=in.readInt();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
//将数据序列化到对象中
dest.writeString(name);
dest.writeInt(age);
}
@Override
public int describeContents() {
//只针对一些特殊的需要描述信息的对象,需要返回1,其他情况返回0就可以
return 0;
}
public static final Creator<Person> CREATOR = new Creator<Person>() {
@Override
public Person createFromParcel(Parcel in) {
// 反序列化,读取数据
return new Person(in);
}
//供反序列化本类数组时调用的
@Override
public Person[] newArray(int size) {
return new Person[size];
}
};
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;
}
}
2.在MainActivity开启序列化
button2=findViewById(R.id.bt_click2);
button2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
Person person=new Person("Simon",23);
Intent intent2=new Intent(MainActivity.this, SerializableActivity.class);
intent2.putExtra("Simon",person);
startActivity(intent2);
}
});
3.在目标Activity获取对象
Intent intent=getIntent();
Person person=intent.getParcelableExtra("Simon");
4.Serializable 和Parcelable的对比
android上应该尽量采用Parcelable,效率至上。
1.编码上:
Serializable代码量少,写起来方便
Parcelable代码多一些
2.效率上:
Parcelable的速度比高十倍以上。(别人测试过)
至于如何选择前面已经说了,就不赘述了。
5.Github
github
觉得有帮助的话可以star!