IPC基础概念
Serializable接口
Serializable接口的实现
1 | public class User implements Serializable { |
序列化和反序列化的实现
1 | //序列化过程 |
serialVersionUID作用
- 序列化时:当一个
User对象被序列化时(比如写入文件),Java运行时环境会把这个serialVersionUID的值也一并写入到字节流中。 - 反序列化时:当程序试图从文件中读取字节流并将其反序列化成一个
User对象时,Java运行时环境会进行一个关键的检查:
- 它会比较文件中的
serialVersionUID和当前JVM中加载的User.class文件计算出的serialVersionUID是否一致。 - 如果两者一致,就认为版本是兼容的,反序列化过程继续,对象被成功创建。
- 如果两者不一致,JVM会认为“你拿旧版本的说明书来组装新版本的零件,可能会出问题”,于是直接抛出
InvalidClassException异常,反序列化失败。
显示设定这个值就相当于你给这个类贴上了一个永久性的、写死的“版本标签”,减少反序列化失败的可能
Parcelable接口
用法实例
1 | public class User implements Parcelable { |
Parcelable方法说明

Serializable和Parcelable的选取
Serializable是Java中的序列化接口,其使用起来简单但开销很大,序列化和反序列化过程需要大量的I/O操作。而Parcelable是Android中的序列化方式,因此更适合Android平台,他的缺点就是使用起来麻烦一些,但效率很高,这是Android推荐的序列化方式。Parcelable主要用在内存序列化上,将对象序列化到存储设备中或者将对象序列化后通过网络传输这两种情况推荐使用Serializable。
Binder
方法一
使用AIDL文件,SDK自动生成Binder类
首先一定要在build.gradle.kts中声明
1
2
3buildFeatures {
aidl=true
}接下来正常操作

方法二
自己创建Binder类
声明一个aidl性质的接口,继承IInterface接口
1
2
3
4
5
6
7
8public interface IBookManager extends IInterface {
static final String DESCRIPTOR="com.example.ipctest.IBookManager";
static final int TRANSACTION_getBookList= IBinder.FIRST_CALL_TRANSACTION+0;
static final int TRANSACTION_addBook= IBinder.FIRST_CALL_TRANSACTION+1;
public List<Book> getBookList() throws RemoteException;
public void addBook(Book book) throws RemoteException;
}实现Stub类和Stub类中的Proxy代理类
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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110public class BookManagerImpl extends Binder implements IBookManager {
public BookManagerImpl(){
this.attachInterface(this,DESCRIPTOR);
}
public static IBookManager asInterface(IBinder obj){
if((obj==null)){
return null;
}
IInterface iin=obj.queryLocalInterface(DESCRIPTOR);
if(((iin!=null)&&(iin instanceof IBookManager))){
return ((IBookManager) iin);
}
return new BookManagerImpl.Proxy(obj);
}
public IBinder asBinder() {
return this;
}
protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
switch (code){
case INTERFACE_TRANSACTION:{
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_getBookList:{
data.enforceInterface(DESCRIPTOR);
List<Book> result=this.getBookList();
reply.writeNoException();
reply.writeTypedList(result);
return true;
}
case TRANSACTION_addBook:{
data.enforceInterface(DESCRIPTOR);
Book arg0;
if((0!=data.readInt())){
arg0=Book.CREATOR.createFromParcel(data);
}else {
arg0=null;
}
this.addBook(arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
public List<Book> getBookList() throws RemoteException {
//TODO待实现
return null;
}
public void addBook(Book book) throws RemoteException {
//TODO待实现
}
private static class Proxy implements IBookManager{
private IBinder mRemote;
Proxy (IBinder remote){
mRemote=remote;
}
public IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor(){
return DESCRIPTOR;
}
public List<Book> getBookList() throws RemoteException {
Parcel data =Parcel.obtain();
Parcel reply = Parcel.obtain();
List<Book> result;
try{
data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(TRANSACTION_getBookList,data,reply,0);
reply.readException();
result=reply.createTypedArrayList(Book.CREATOR);
}finally {
reply.recycle();
data.recycle();
}
return result;
}
public void addBook(Book book) throws RemoteException {
Parcel data =Parcel.obtain();
Parcel reply = Parcel.obtain();
try{
data.writeInterfaceToken(DESCRIPTOR);
if((book!=null)){
data.writeInt(1);
book.writeToParcel(data,0);
}else {
data.writeInt(0);
}
mRemote.transact(TRANSACTION_addBook,data,reply,0);
reply.readException();
}finally {
reply.recycle();
data.recycle();
}
}
}
}名词解释
DESCRIPTOR
Binder的唯一标识,一般用Binder的类名表示
asInterface(android.os,IBinder obj)
用于将服务端的Binder对象转换成客户端所需要的AIDL接口类型对象,这种转换过程区分进程,如果客户端和服务端位于同一进程,那么此方法返回的就是服务端的Stub对象本身,否返回的就是系统封装后的Stub.proxy对象
asBinder
此方法用于返回当前的Binder对象
onTransact
这个方法运行在服务端的Binder线池中
Proxy#getBookList
这个方法运行在客户端,内部实现:首先创建该方法所需要的输入型Parcel对象_data,输出型Parcel对象 _reply和返回值对象List,然后把该方法的参数写入 _data中,接着调用transact方法来发起RPC(远程过程调用)请求,同时当前线程挂起;然后服务端的onTransact方法会被调用,直到RPC过程返回后,当前线程继续执行,并从reply中取出RPC过程的返回结果;最后返回 _reply中的数据
Proxy#addBook
过程和上面的一样,没有返回值不需要从 _reply中取出返回值
linkToDeath和unlinkToDeath
为了解决Binder死亡对功能的影响提供了这俩方法(为了监听远程进程的死亡事件)
给Binder设置死亡代理:
首先声明一个DeathRecipient对象,移除之前的binder代理并重新绑定远程服务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21private IBinder.DeathRecipient mDeathRecipient=new IBinder.DeathRecipient(){
/**
* 当远程服务的 Binder 死亡时(即其所在进程终止),这个方法会被回调。
*/
public void binderDied() {
// 1. 安全检查,虽然理论上此时 mBookManager 不会为 null,但加上更健壮
if(mBookManager==null) return;
// 2. 解除死亡监听
// 既然已经收到了死亡通知,就不再需要监听了,所以要解除注册,防止内存泄漏。
mBookManager.asBinder.unlinkToDeath(mDeathRecipient,0);
// 3. 清理无效的代理对象
// 远程服务已经死亡,这个 mBookManager 代理对象也失效了,立即设为 null,
// 防止应用的其他地方误用这个“已死亡”的对象,导致 DeadObjectException。
mBookManager=null;
// 4. 实现重连机制(关键步骤)
// 这是最重要的一步,你可以在这里编写逻辑来重新绑定远程服务。
// 比如可以启动一个新的 bindService 请求,这样当远程服务恢复后,你的客户端就能自动重新连接上。
//TODO:这里重新绑定远程Service
}
};设置死亡代理
1
2
3
4//将底层的 IBinder 对象转换为客户端可直接调用的 AIDL 接口代理对象 (mService)。
mService=IMessageBoxManager.Stub.asInterface(binder);
//给这个 binder 连接注册一个“死亡讣告”接收者 (mDeathRecipient)。
binder.linkToDeath(mDeathRecipient,0);
**注:**通过Binder的方法isBinderAlive也可以判断Binder是否死亡




