Android IPC:IPC基础概念和安卓中的ipc方式
要点
serializable、parcelable接口可以完成对象序列化过程。
1、 当我们需要通过intent和Binder传输数据的时候,就需要使用serializable,或者parcelable。
2、我们需要把对象持久化到设备上,或者通过网络传输给其他客户端这时候也需要serializable来完成对象持久化。
一 、Serializable接口
1、简介:
Serializable是java提供的一个序列化的接口,这个接口是个空实现。为对象提供标准的序列化和反序列化操作。
2、使用语法及其栗子
语法:
定义一个类实现Serializable接口,然后声明个serialVersionUID即可。
如上:十分简单,甚至serialVersionUID也不是必须的。我们不声明这个值也可以完成序列化,但是会对反序列化产生影响。
栗子:
/**
* serializable 案例
*/
private void serializableTest() throws Exception {
User user = new User(0, "Tom", true);
//对象写入文件 ---序列化过程
ObjectOutputStream oos = new ObjectOutputStream(openFileOutput("cache.txt",MODE_PRIVATE));
oos.writeObject(user);
oos.close();
// 对象读取 --- 反序列化过程
ObjectInputStream ois = new ObjectInputStream(openFileInput("cache.txt"));
User newUser = (User) ois.readObject();
ois.close();
Log.i(TAG, "newUser"+newUser.userName);
Log.i(TAG, "newUser"+newUser.userId);
Log.i(TAG, "newUser"+newUser.isMale);
}
再次了解serialVersionUID:
不指定serialVersionUID我们也可以完成正常的序列化,我们要明白系统既然提供了这个类,必然是有用的,这个类是用来辅助序列化和反序列化过程的。原则上序列化后的数据中的serialVersionUID只有和当前类的serialVersionUID相同才能够正常的反序列化。
serialVersionUID的工作机制:
序列化的时候系统会把当前类的serialVersionUID写入序列化的文件中,当反序列化的时候系统会检测当前文件中的serialVersionUID是否和当前类的serialVersionUID一致,如果一致这个时候可以反序列化成功,否则就说明当前类和序列化的类相比发生了某些变换,比如成员变量的数量、类型可能发生了改变,这个时候是无法正常反序列化的.
-
我们手动指定serialVersionUID时:
这样序列化和反序列化的serialVersionUID是相同的,因此可以正常反序列化。 -
未指定指定serialVersionUID的值时:
反序列化时当前类有所改变(也就是序列化后,修改类的字段等等,在进行反序列化),比如增加或减少了某些成员变量,那么系统会重新计算当前类的hash值并把它赋值给serialVersionUID,这个时候当前类的serialVersionUID就和序列化数据中的serialVersionUID不一致,于是反序列化失败,程序就会出现crash。
所以当我们手动指定了serialVersionUID的值,就可以很大程度上避免了反序列化的失败。但是如果类结构发生了非常规性改变,比如修改了类名,修改了成员变量的类型,这个时候尽管serialVersionUID验证通过了,但是反序列化还是会失败,因为类结构发生了毁灭性的改变。
ps:注意:静态成员变量不属于对象,所以不会参与序列化过程。其次用transient关键字标记的成员变量不参与序列化过程。
有关serialVersionUID 可以参考:http://www.cnblogs.com/duanxz/p/3511695.html
二、Parcelable接口
Parcelable也是一个接口只要实现这个接口一个类的对象就可以实现序列化,并可以通过intent,Binder来传递。
栗子:
package com.example.administrator.androiddevelopmentart;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Create by SunnyDay on 2019/03/31
*/
public class User implements Parcelable {
public int userId;
public String userName;
public boolean isMale;
public Book book;
public User(int userId, String userName, boolean isMale) {
this.userId = userId;
this.userName = userName;
this.isMale = isMale;
}
protected User(Parcel in) {
userId = in.readInt();
userName = in.readString();
isMale = in.readByte() != 0;
book = in.readParcelable(Thread.currentThread().getContextClassLoader());
}
public static final Creator<User> CREATOR = new Creator<User>() {
@Override
public User createFromParcel(Parcel in) {
return new User(in);
}
@Override
public User[] newArray(int size) {
return new User[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(userId);
dest.writeString(userName);
dest.writeByte((byte) (isMale ? 1 : 0));
dest.writeParcelable((Parcelable) book, 0);
}
}
如图:只需定义类实现Parcelable接口即可,这时编译器提示实现Parcelable接口中的方法我们实现即可,在根据提示实现CREATOR(反序列化操作)就完事了。
Parcelable重载方法介绍:
-
writeToParcel(Parcel dest, int flags)
进行序列化操作,可以调用Parcel 的writexxx写相应的类型数据。
其中flags的标识有0或者1,为1标识当前对象需要作为返回值返回,不能立即释放资源,几乎所有情况都为0 -
createFromParcel(Parcel in)
从序列化后的对象中创建原始对象 -
newArray(int size)
创建指定长度原始类型数组。 -
User(Parcel in)
反序列化操作,通过系统为你生成的构造(如下图此构造系统根据你的类生成)传递Parcel in参数来进行反序列化 -
describeContents
返回对象的内容描述,如果含有文件描述符返回1否则返回0,一般为0
ps:在 User(Parcel in)中book是另一个可序列化对象(作为本类的成员),所以他的反序列化过程需要传递当前线程上下文的类加载器。否则报无法找到类的错误。
系统为我们提供了许多实现Parcelable接口的类,他们可以直接序列化的,比如intent,Bundle,Bitmap。同时List、map也可以序列化,前提是存的元素可以序列化。
Parcelable和Serializable区别:
-
Serializable
java序列化接口,其使用起来简单但是开销非常大。序列化和反序列化过程需要大量io操作。 -
Parcelable
android序列化接口,缺点使用起来麻烦,但是效率高。Parcelable主要用于内存序列化上。通过Parcelable将对象序列化到设备中或者将对象序列化后通过网络传输也是可以的。但是这个过程会复杂建议使用Serializable。
三、Binder
由于代码较多不在手打,直接大树乘凉哈(下面的参考和开发艺术的案例一致)
参考1:
https://blog.****.net/gkk000/article/details/55001832
参考2:
https://www.cnblogs.com/rookiechen/p/5352053.html
此处内容较难,先留下笔记,以后回味。(再详细整理)
四、安卓中的ipc方式
未完待续、、、、