AIDL(Android Interface Definition Language)
来累,即Android
接口定義語言视乐。為了實現(xiàn)Android系統(tǒng)中進程與進程之間的通信(IPC)
陨舱,而提供的一種通信方式宅广。
建立步驟
以AndroidStudio
為例氛改,具體步驟如下:
- 在
java
同級目錄下創(chuàng)建一個名為aidl
的目錄恬口; - 創(chuàng)建一個
aidl
文件; - 執(zhí)行
rebuild project
即可自動生成.java
文件弥锄,它的完整路徑是:app->build->generated->source->aidl->debug->com->lypeer->ipcclient->BookManager.jav
丧靡;
類圖
在AIDL接口中有靜態(tài)內(nèi)部類類Stub和add()蟆沫、subtraction()方法,在靜態(tài)內(nèi)部類中存在內(nèi)部類Proxy温治。
代碼分析
- RemoteService初始化的執(zhí)行流程是RemoteService()->onCreate()->onBind()饭庞,這里我們將AIDL定義的接口方法進行了重寫,實現(xiàn)了具體功能罐盔。接著在onBind()方法里將Stub對象即IBinder對象返回出去但绕。
public class RemoteService extends Service {
private IBinder iBinder;
public RemoteService() {
}
@Override
public void onCreate() {
super.onCreate();
//初始化Binder救崔,就是初始化Stub惶看,就是將Stub中的DESCRIPTION描述標(biāo)識依附到到Interface中記錄下來。方便客戶端獲取AIDL對象六孵,調(diào)用接口方法纬黎。
iBinder = new MyBinder();
}
@Override
public IBinder onBind(Intent intent) {
return iBinder;
}
class MyBinder extends IMyAidlInterface.Stub{
@Override
public void add(int a, int b) throws RemoteException {
//add()方法的具體實現(xiàn)
}
@Override
public int subtraction(int a, int b) throws RemoteException {
////subtraction()方法的具體實現(xiàn)
return 0;
}
}
}
- 客戶端調(diào)用bindService以后,Service中的onCreate()劫窒、onBinder()方法依次執(zhí)行本今。會將IBinder對象返回到onServiceConnected方法中。從而借助于Stub中的asInterface方法去獲取本地AIDL對象或者實例化Proxy獲取遠(yuǎn)程AIDL對象主巍,進而調(diào)用接口中的方法冠息。
//綁定服務(wù)
bindService(new Intent(this, RemoteService.class), new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
//在RemoteService初始化的時候會生成IBinder對象,服務(wù)連接成功會返回IBinder孕索。
//通過IMyAidlInterface.Stub中的asInterface方法根據(jù)Stub的DESCRIPTOR獲取AIDL對象,調(diào)用接口中的方法
IMyAidlInterface aidlInterface = IMyAidlInterface.Stub.asInterface(iBinder);
try {
aidlInterface.add(1,1);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
},BIND_AUTO_CREATE);
- asInterface方法中執(zhí)行了很重要的代碼逛艰,它會先根據(jù)DESCRIPTION搜索本地是否存在AIDL對象,如果存在搞旭,則return散怖;否則就實例化Proxy,創(chuàng)建遠(yuǎn)程IBinder代理對象肄渗。
/**
* Cast an IBinder object into an com.yolo.h5demo.IMyAidlInterface interface,
* generating a proxy if needed.
*/
public static com.yolo.h5demo.IMyAidlInterface asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
//搜索本地是否已經(jīng)有可用的對象了
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.yolo.h5demo.IMyAidlInterface))) {
return ((com.yolo.h5demo.IMyAidlInterface) iin);
}
//新建遠(yuǎn)程Proxy對象镇眷,內(nèi)部實例化Binder
return new com.yolo.h5demo.IMyAidlInterface.Stub.Proxy(obj);
}
- Proxy就是客戶端和服務(wù)端通信的代理類了,通過transact方法處理客戶端與服務(wù)端的數(shù)據(jù)流。正是由于asInterface獲取到IBinder代理對象即Proxy翎嫡,才會執(zhí)行transact方法將客戶端數(shù)據(jù)和請求發(fā)送到服務(wù)端欠动。
@Override
public void add(int a, int b) throws android.os.RemoteException {
//_data用來存儲流向服務(wù)端的數(shù)據(jù)流,
//_reply用來存儲服務(wù)端流回客戶端的數(shù)據(jù)流
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(a);
_data.writeInt(b);
////調(diào)用 transact() 方法將方法id和兩個 Parcel 容器傳過去
mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
////從_reply中取出服務(wù)端執(zhí)行方法的結(jié)果
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
- 服務(wù)端則根據(jù)參數(shù)惑申,通過switch語句執(zhí)行不同操作翁垂,調(diào)用服務(wù)端中對應(yīng)的方法,并將返回結(jié)果寫入reply流
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_add: {
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();
this.add(_arg0, _arg1);
reply.writeNoException();
return true;
}
case TRANSACTION_subtraction: {
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();
int _result = this.subtraction(_arg0, _arg1);
reply.writeNoException();
reply.writeInt(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
補充
正如《Android內(nèi)核剖析》一書所言:重載onTransact()
函數(shù)的主要內(nèi)容是把onTransact()
函數(shù)的參數(shù)轉(zhuǎn)換為服務(wù)函數(shù)的參數(shù)硝桩,而 onTransact()
函數(shù)的參數(shù)來源是客戶端調(diào)用transact()
函數(shù)時輸入的沿猜,因此,如果transact()
有固定格式的輸入碗脊,那么onTransact()
就會有固定格式的輸出啼肩。
客戶端訪問遠(yuǎn)程服務(wù)橄妆,都需要通過mRemote對象,并調(diào)用transact方法祈坠。而在Binder驅(qū)動中也重載了transact方法害碾。
對開發(fā)人員而言,客戶端似乎直接調(diào)用了遠(yuǎn)程服務(wù)的Binder赦拘,而事實上是通過底層Binder驅(qū)動進行了中轉(zhuǎn)慌随。即存在兩個Binder對象,一個是服務(wù)端的躺同,另一個是Binder驅(qū)動中的阁猜。注意服務(wù)端會產(chǎn)生一個隱藏線程處理消息。
各位大神蹋艺,有描述不對之處還望指正剃袍!