[027]十分钟让你明白AIDL
前言
我在[003]AIDL是什么中介绍的AIDL,但是好像还有朋友不明白问我,那我就来写一个终极版的文章,让你十分钟彻底明白AIDL,以下代码全为手写。
目标
Server进程注册一个Calculator服务到ServiceManager,该Calculator服务提供add和minus两个接口
Client进程通过ServiceManager获得Calculator服务的代理类,通过Binder调用add和minus两个接口
1、没有AIDL的世界
1.1 Server进程
class Calculator extends Binder {
private static final int CODE_ADD = 1;
private static final int CODE_MINUS = 2;
@Override
protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException {
if (code == CODE_ADD) {
int a = data.readInt();
int b = data.readInt();
reply.writeInt(a + b);
return true;
} else if (code == CODE_MINUS) {
int a = data.readInt();
int b = data.readInt();
reply.writeInt(a + b);
return true;
}
return super.onTransact(code, data, reply, flags);
}
}
void main() {
//注册binder服务
ServiceManager.addService("calculator", new Calculator());
}
1.2 Client进程
private static final int CODE_ADD = 1;
private static final int CODE_MINUS = 2;
int add(int a, int b) {
IBinder mClient = ServiceManager.getService("calculator");//BinderProxy
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInt(a);
data.writeInt(b);
mClient.transact(CODE_ADD, data, reply, 0);
int result = reply.readInt();
return result;
}
int minus(int a, int b) {
IBinder mClient = ServiceManager.getService("calculator");//BinderProxy
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInt(a);
data.writeInt(b);
mClient.transact(CODE_MINUS, data, reply, 0);
int result = reply.readInt();
return result;
}
2、有AIDL的世界
ICalculator.aidl文件
//aidl
interface ICalculator {
int add(int a, int b);
int minus(int a, int b);
}
2.1 Server进程
与1.1中代码比较,我们发现,我们不是直接继承Binder,而是继承ICalculator.Stub,我们只需专注写add和minus接口的实现,不需要在Binder类中的onTransact写一堆if else和Parcel.read write
class Calculator extends ICalculator.Stub {
@Override
public int add(int a, int b) {
return a + b;
}
@Override
public int minus(int a, int b) {
return a - b;
}
}
void main() {
//注册binder服务
ServiceManager.addService("calculator", new Calculator());
}
2.2 Client进程
与1.2中代码比较,我们发现,我们不需要写Parcel.read write和BinderProxy.transact,而是用BinderProxy对象构造一个ICalculator.Stub.Proxy对象,然后直接调用ICalculator.Stub.Proxy的add和minus
int add(int a, int b) {
IBinder mClient = ServiceManager.getService("calculator");//BinderProxy
return new ICalculator.Stub.Proxy(mClient).add(a, b);
}
int minus(int a, int b) {
IBinder mClient = ServiceManager.getService("calculator");//BinderProxy
return new ICalculator.Stub.Proxy(mClient).minus(a, b);
}
3、AIDL自动生成了什么代码
ICalculator.aidl生成的代码如下,有三个部分组成,我们后面仔细分析
ICalculator接口
ICalculator.Stub类
ICalculator.Stub.Proxy类
interface ICalculator {//看3.1分析
int add(int a, int b);
int minus(int a, int b);
abstract static class Stub extends Binder implements ICalculator {//看3.2分析
private static final int CODE_ADD = 1;
private static final int CODE_MINUS = 2;
@Override
protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException {
if (code == CODE_ADD) {
int a = data.readInt();
int b = data.readInt();
reply.writeInt(add(a, b));
return true;
} else if (code == CODE_MINUS) {
int a = data.readInt();
int b = data.readInt();
reply.writeInt(minus(a, b));
return true;
}
return super.onTransact(code, data, reply, flags);
}
abstract public int add(int a, int b);
abstract public int minus(int a, int b);
public static class Proxy implements ICalculator {//看3.3分析
private IBinder remote;
public Proxy(IBinder remote) {
this.remote = remote;
}
@Override
public int add(int a, int b) {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInt(a);
data.writeInt(b);
remote.transact(CODE_ADD, data, reply, 0);
int result = reply.readInt();
return result;
}
@Override
public int minus(int a, int b) {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInt(a);
data.writeInt(b);
remote.transact(CODE_MINUS, data, reply, 0);
int result = reply.readInt();
return result;
}
}
}
}
3.1 ICalculator接口
看起来和aidl文件差不多
interface ICalculator {
int add(int a, int b);
int minus(int a, int b);
}
3.2 ICalculator.Stub类
继承于Binder,实现ICalculator接口,但是是空实现,然后在onTransact方法中调用空实现的add和minus接口
abstract static class Stub extends Binder implements ICalculator {
private static final int CODE_ADD = 1;
private static final int CODE_MINUS = 2;
@Override
protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException {
if (code == CODE_ADD) {
int a = data.readInt();
int b = data.readInt();
reply.writeInt(add(a, b));
return true;
} else if (code == CODE_MINUS) {
int a = data.readInt();
int b = data.readInt();
reply.writeInt(minus(a, b));
return true;
}
return super.onTransact(code, data, reply, flags);
}
abstract public int add(int a, int b);
abstract public int minus(int a, int b);
}
3.3 ICalculator.Stub.Proxy类
用BinderProxy构造ICalculator.Stub.Proxy,把调用ICalculator.Stub.Proxy的add和minus接口转化成Parcel.write,read和BinderProxy.transact代码。
public static class Proxy implements ICalculator {
private IBinder remote;
public Proxy(IBinder remote) {
this.remote = remote;
}
@Override
public int add(int a, int b) {
Parcel data = Parcel.obtain();
data.writeInt(a);
data.writeInt(b);
Parcel reply = Parcel.obtain();
remote.transact(CODE_ADD, data, reply, 0);
int result = reply.readInt();
return result;
}
@Override
public int minus(int a, int b) {
Parcel data = Parcel.obtain();
data.writeInt(a);
data.writeInt(b);
Parcel reply = Parcel.obtain();
remote.transact(CODE_MINUS, data, reply, 0);
int result = reply.readInt();
return result;
}
}
总结
看完应该明白了AIDL作用主要有
a.偷懒,少很多代码,尤其是你要写上百个方法的时候,AIDL就派上大用场了。
b.让服务端更专注接口的实现,而减少犯错误的可能性
c.规范client端和server端的接口定义,有助于代码的迭代
当然这是我自己写的伪代码,AIDL真正生成的代码更加复杂一点,但这些伪代码就是AIDL核心点。
思考
oneway的这个语法对AIDL生成的代码有什么影响,或者你们自己写一下oneway的方法AIDL生成的伪代码