前言
我在[003]AIDL是什麼中介紹的AIDL,但是好像還有朋友不明白問我,那我就來寫一個終極版的文章,讓你十分鐘徹底明白AIDL,以下代碼全爲手寫。
目標
Server進程註冊一個Binder服務到SM,該Binder服務提供兩個接口:add和minus
Client 進程通過SM獲得Binder服務的代理類BinderProxy,並調用兩個接口add,minus
1 沒有AIDL的世界
1.1 Server進程
class CommandBinder extends Binder {
@Override
protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException {
if (code == 1) {
int a = data.readInt();
int b = data.readInt();
reply.writeInt(a + b);
return true;
} else if (code == 2) {
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("command", new CommandBinder());
}
1.2 Client進程
int add(int a, int b) {
int code = 1;
BinderProxy mClient = ServiceManager.getService("command");
Parcel data = Parcel.obtain();
data.writeInt(a);
data.writeInt(b);
Parcel reply = Parcel.obtain();
mClient.transact(code, data, reply, 0);//flag設置成0,調用這個方法會跨進程調用Binder服務類中onTransact方法
int result = reply.readInt();
return result;
}
int minus(int a, int b) {
int code = 2;
BinderProxy mClient = ServiceManager.getService("command");
Parcel data = Parcel.obtain();
data.writeInt(a);
data.writeInt(b);
Parcel reply = Parcel.obtain();
mClient.transact(code, data, reply, 0);//flag設置成0,調用這個方法會跨進程調用Binder服務類中onTransact方法
int result = reply.readInt();
return result;
}
2 有AIDL的世界
AIDL文件
//aidl
interface ICommand {
int add(int a, int b);
int minus(int a, int b);
}
2.1 Server進程
與1.1中代碼比較,我們發現,我們不是直接繼承Binder,而是繼承aidl文件自動生成ICommandBinder,我們只需專注寫add和minus接口的實現,不需要在Binder類中的onTransact寫一堆if else代碼和Parcel.read write.
class ADILCommandBinder extends ICommandBinder {
@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("command", new ADILCommandBinder());
}
2.2 Client進程
與1.2中代碼比較,我們發現,我們不需要寫Parcel.read write和BinderProxy.transact,而是用BinderProxy對象構造一個CommandBinderProxy對象,然後直接調用CommandBinderProxy的add和minus
int add(int a, int b) {
BinderProxy mClient = ServiceManager.getService("command");
return new CommandBinderProxy(mClient).add(a, b);
}
int minus(int a, int b) {
BinderProxy mClient = ServiceManager.getService("command");
return new CommandBinderProxy(mClient).minus(a, b);
}
3 ADIL自動生成了什麼代碼
生成了三個部分:ICommand,ICommandBinder,CommandBinderProxy
3.1 ICommand
看起來和aidl文件差不多
interface ICommand {
int add(int a, int b);
int minus(int a, int b);
}
3.2 ICommandBinder
繼承於Binder,並實現ICommand,然後在onTransact方法中調用還沒有實現的add和minus方法
abstract public class ICommandBinder extends Binder implements ICommand {
int add = 1;
int minus = 2;
@Override
protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException {
if (code == 1) {
int a = data.readInt();
int b = data.readInt();
reply.writeInt(add(a, b));
return true;
} else if (code == 2) {
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 CommandBinderProxy
對BinderProxy進行封裝,把調用CommandBinderProxy的add轉化成Parcel.write,read和BinderProxy.transact代碼。
public class CommandBinderProxy implements ICommand {
private BinderProxy remote;
int add = 1;
int minus = 2;
public CommandBinderProxy(BinderProxy 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(add, data, reply, 0);
int result = reply.readInt();
return result;
}
@Override
public int minus(int a, int b) {
int code = 2;
Parcel data = Parcel.obtain();
data.writeInt(a);
data.writeInt(b);
Parcel reply = Parcel.obtain();
remote.transact(code, data, reply, 0);
int result = reply.readInt();
return result;
}
}
總結
看完應該明白了AIDL作用主要有
a.偷懶,少很多代碼,尤其是你要寫上百個方法的時候,AIDL就派上大用場了。
b.讓服務端更專注接口的實現,而減少犯錯誤的可能性
c.規範client端和server端的接口定義,有助於代碼的迭代
當然這是我自己寫的僞代碼,AIDL真正生成的代碼比較複雜,但這些僞代碼就是AIDL核心點。
思考
oneway的這個語法對AIDL生成的代碼有什麼影響,或者你們自己寫一下oneway的方法AIDL生成的僞代碼