多进程通信基础概念
序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。简单来说,“序列化”就是将运行时的对象状态转换成二进制,然后保存到流、内存或者通过网络传输给其他端。
1 Serializable 接口
需要本地存储时,使用Serializable接口。因为Parcelable有个明显的缺点:不能使用在要将数据存储在磁盘上的情况(如:永久性保存对象,保存对象的字节序列到本地文件中),因为Parcelable本质上是为了更好的实现对象在 IPC间传递,并不是一个通用的序列化机制,当改变任何Parcelable中数据的底层实现都可能导致之前的数据不可读取。
实现序列化接口
public class User implements Serializable {
private static final long serialVersionUID = 2638636864705079855L;
private String userName;
private int userId;
private boolean isMale;
public User(String userName, int userId, boolean isMale) {
this.userName = userName;
this.userId = userId;
this.isMale = isMale;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public boolean isMale() {
return isMale;
}
public void setMale(boolean male) {
isMale = male;
}
}
默认实现 Serializable 不会自动创建 serialVersionUID 属性,为了提示我们及时创建 serialVersionUID ,可以在设置中搜索 serializable 然后选择下图所示的几个选项,为那些没有声明 serialVersionUID 属性的类以及内部类添加一个警告。
对象序列化过程
User user = new User("lwj", 0, false);
try {
File exDir = Environment.getExternalStorageDirectory();
String filename="test.txt";
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File(exDir,filename)));
oos.writeObject(user);
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
对象反序列化过程
try {
File exDir = Environment.getExternalStorageDirectory();
String filename="test.txt";
ObjectInputStream ojs = new ObjectInputStream(new FileInputStream(new File(exDir,filename)));
User user= (User) ojs.readObject();
Log.e(TAG,"name:"+user.getUserName()+",id:"+user.getUserId()+",male:"+user.isMale());
ojs.close();
} catch (Exception e) {
e.printStackTrace();
}
2 Parcelable接口
当需要内存较多时使用Parcelable接口。 Serializable在序列化的时候会产生大量的临时变量,从而引起频繁的GC,而相比之下 Parcelable的性能更高,所以当在使用内存时(如:序列化对象在网络中传递对象或序列化在进程间传递对象),更推荐使用Parcelable接口。
实现序列化接口
public class User implements Parcelable {
private String userName;
private int userId;
private boolean isMale;
public User(String userName, int userId, boolean isMale) {
this.userName = userName;
this.userId = userId;
this.isMale = isMale;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public boolean isMale() {
return isMale;
}
public void setMale(boolean male) {
isMale = male;
}
/**
* @param in
*
* 从序列化后的对象中创建原始对象
*/
protected User(Parcel in) {
userName = in.readString();
userId = in.readInt();
isMale = in.readByte() != 0;
}
public static final Creator<User> CREATOR = new Creator<User>() {
/**
* Create a new instance of the Parcelable class, instantiating it
* from the given Parcel whose data had previously been written by
* {@link Parcelable#writeToParcel Parcelable.writeToParcel()}.
*
* @param source The Parcel to read the object's data from.
* @return Returns a new instance of the Parcelable class.
*
* 从序列化后的对象中创建原始对象
*/
@Override
public User createFromParcel(Parcel in) {
return new User(in);
}
/**
* Create a new array of the Parcelable class.
*
* @param size Size of the array.
* @return Returns an array of the Parcelable class, with every entry
* initialized to null.
*
* 创建指定长度的原始对象数组
*/
@Override
public User[] newArray(int size) {
return new User[size];
}
};
/**
* Describe the kinds of special objects contained in this Parcelable
* instance's marshaled representation. For example, if the object will
* include a file descriptor in the output of {@link #writeToParcel(Parcel, int)},
* the return value of this method must include the
* {@link #CONTENTS_FILE_DESCRIPTOR} bit.
*
* @return a bitmask indicating the set of special object types marshaled
* by this Parcelable object instance.
*
* 返回当前对象的内容描述.
* 如果含有文件描述符,返回1(CONTENTS_FILE_DESCRIPTOR),否则返回0, 几乎所有情况都返回0。
*/
@Override
public int describeContents() {
return 0;
}
/**
* Flatten this object in to a Parcel.
*
* @param dest The Parcel in which the object should be written.
* @param flags Additional flags about how the object should be written.
* May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}.
*
* 将当前对象写入序列化结构中,其中flags标识有两种值:0或者1 (PARCELABLE_WRITE_RETURN_VALUE).
* 为1时标识当前对象需要作为返回值返回,不 能立即释放资源,几乎所有情况部为0
*
*/
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(userName);
dest.writeInt(userId);
dest.writeByte((byte) (isMale ? 1 : 0));
}
}
对象序列化过程
User user = new User("lwj", 1, true);
Intent intent =new Intent(this,SecondActivity.class);
// 传输方式一,intent直接调用putExtra
// public Intent putExtra(String name, Serializable value)
intent.putExtra("user",user);
// 传输方式二,intent利用putExtras 传入bundle
/* Bundle bundle = new Bundle();
bundle.putParcelable("user",user);
intent.putExtras(bundle);*/
startActivity(intent);
对象反序列化过程
User user= (User) getIntent().getParcelableExtra("user");
Log.e(TAG,"name:"+user.getUserName()+",id:"+user.getUserId()+",male:"+user.isMale());
3 Binder
直观来说,Binder是Android中的一个类,它实现了IBinder接口。从进程间通信角度来说, Binder是Android中的一种跨进程通信方式,Binder还可以理解为一种虚拟的物理设备, 它的设备驱动是/dev/binder,该通信方式在Linux中没有;从Android Framework角度来说, Binder 是 ServiceManager 连接各种 Manager (ActivityManager、WindowManager,等等)和 相应ManagerService的桥梁;从Android应用层来说,Binder是客户端和服务端进行通信 的媒介,当bindService的时候,服务端会返回一个包含了服务端业务调用的Binder对象, 通过这个Binder对象,客户端就可以获取服务端提供的服务或者数据,这里的服务包括普 通服务和基于AIDL的服务。