持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第11天,点击查看活动详情
前言
上一篇文章我们使用AIDL文件实现了IPC通信,在build的过程中as帮我们生成了很多模板化的代码,今天为了深入理解Binder机制的数据传输,我们自己动手实现一下Binder的通信,把AS帮我们生成的那些代码自己手写出来~
为了深入理解Binder的通信机制,我们还是用Person服务
一、服务端
1.1 定义服务端接口
public interface PersonInterface {
void addPerson(Person person);
List<Person> getPersonList();
}
1.2 声明序列化对象
这里声明的对象还是不变
1.3 定义Binder提供的代理对象
public class Proxy implements PersonInterface {
private IBinder iBinder;
public Proxy(IBinder iBinder) {
this.iBinder = iBinder;
}
@Override
public void addPerson(Person person) {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(DESCRIPTOR);
if (person != null) {
data.writeInt(1);
person.writeToParcel(data, 0);
} else {
data.writeInt(0);
}
try {
iBinder.transact(BinderObj.TRANSACTION_ADDPerson, data, reply, 0);
} catch (RemoteException e) {
e.printStackTrace();
} finally {
reply.recycle();
data.recycle();
}
}
@Override
public List<Person> getPersonList() {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
List<Person> result = null;
try {
data.writeInterfaceToken(DESCRIPTOR);
iBinder.transact(BinderObj.TRANSACTION_GETPerson, data, reply, 0);
reply.readException();
result = reply.createTypedArrayList(Person.CREATOR);
} catch (RemoteException e) {
e.printStackTrace();
} finally {
reply.recycle();
data.recycle();
}
return result;
}
@Override
public IBinder asBinder() {
return null;
}
}
这里提供的代理对象主要就是通过Parcel将数据序列化,然后调用remote.transact()将方法的code,以及入参的data传递过去
1.4 自定义Binder
public static PersonInterface asInterface(IBinder iBinder) {
IInterface iInterface = iBinder.queryLocalInterface(DESCRIPTOR);
if (null != iInterface && iInterface instanceof PersonInterface) {
return (PersonInterface) iBinder;
}
return new Proxy(iBinder);
}
这里我们的Binder也根据是否在同一进程提供不同的服务端对象
1.5 自定义服务端服务
1.6 注册服务
<service
android:name=".MyService"
android:enabled="true"
android:exported="true" />
二、客户端使用接口
2.1 复制服务端接口
客户端需要将服务端提供的接口以及序列化的对象已经Binder代理拷贝到相应包路径下
2.2 使用代理对象
客户端的使用方法还是和aidl使用的步骤是类似的
总结
没有使用aidl文件,我们也实现了进程间的IPC通信,而BinderObj文件的实际逻辑也与aidl模板生成的代码逻辑类似.都是在onTransact函数中进行关键数据的传输,另外也提供了代理生成的具体方法
- 从Server进程来看,Binder是存在的实体对象,client通过transact()函数,经过Binder驱动,最终回调到Binder实体的onTransact()函数中
- 从Client进程来看,Binder指的是Binder代理对象,时Binder实体对象的一个远程代理,通过Binder驱动与服务端进行交互.