AIDL簡介
AIDL是對以 Binder 為核心的跨進程通信機制的進一步封裝某抓,使得這個過程更加簡化惰瓜,只暴露出非常必要的開發(fā)者需要實現(xiàn)的接口崎坊,讓開發(fā)人員實現(xiàn)業(yè)務邏輯。顧名思義曲尸,Android 接口定義語言另患。
既然還是以針對跨進程訪問蛾绎,不過就是客戶端進程和服務端服務進程秘通,且最好的使用場景是客戶端進程和服務端進程不在同一個進程中。而訪問和通信基礎實際上來自于 Binder 機制第股。下面夕吻,首先我們針對上面這些語言中出現(xiàn)的關鍵詞進行解析繁仁,即客戶端進程黄虱,服務進程捻浦,Binder。
客戶端進程
客戶端昧识,我們都知道這是一個相對于服務端而言的概念盗扒。
客戶端通常并不處理具體邏輯,而只是請求向服務端請求結(jié)果朵耕,然后對結(jié)果進行處理淋叶。即煞檩,向服務端發(fā)出request斟湃,然后有服務端進行業(yè)務邏輯處理,然后返回給客戶端response注暗,客戶端拿到response捆昏,做進一步處理(比如UI展示等)毙沾。
在Android應用開發(fā)過程中骗卜,客戶端可以是任何組件,我們常用的activity左胞,service(相對于另外一個service而言寇仓,它就是一個客戶端)等。
服務端進程
說到服務端烤宙,下意識會想到服務器遍烦。服務端的優(yōu)點在于,擁有強大的業(yè)務處理能力躺枕,實現(xiàn)了業(yè)務處理的集中管理服猪,同時還可能增加更多的安全屏障屯远。
在Android應用開發(fā)中蔓姚,各種**ServiceManager都是服務端進程,或者我們實現(xiàn)的Service慨丐,也可以作為服務端進程。
說到Service泄私,提一點題外話房揭,來自于官網(wǎng)對Service的說明:
Service(服務)基本上分為兩種形式:
啟動
當應用組件(如 Activity)通過調(diào)用 startService()
啟動服務時备闲,服務即處于“啟動”狀態(tài)。一旦啟動捅暴,服務即可在后臺無限期運行恬砂,即使啟動服務的組件已被銷毀也不受影響。 已啟動的服務通常是執(zhí)行單一操作蓬痒,而且不會將結(jié)果返回給調(diào)用方泻骤。例如,它可能通過網(wǎng)絡下載或上傳文件梧奢。 操作完成后狱掂,服務會自行停止運行。
綁定
當應用組件通過調(diào)用 bindService()
綁定到服務時亲轨,服務即處于“綁定”狀態(tài)趋惨。綁定服務提供了一個客戶端-服務器接口,允許組件與服務進行交互惦蚊、發(fā)送請求器虾、獲取結(jié)果,甚至是利用進程間通信 (IPC) 跨進程執(zhí)行這些操作蹦锋。 僅當與另一個應用組件綁定時兆沙,綁定服務才會運行。 多個組件可以同時綁定到該服務莉掂,但全部取消綁定后挤悉,該服務即會被銷毀。
通過上面巫湘,我們應該可以看到 bindService 的優(yōu)勢和使用場景装悲,這也就是為什么有時候我們需要定義客戶端,定義服務端尚氛,主要還是便于交互啊诀诊。當然,你說我不使用這種方式阅嘶,就不能實現(xiàn)和服務的交互了嗎属瓣?當然不是啊,實現(xiàn)方式肯定不止一種讯柔,但是這種方式無疑是最方便的吧抡蛙。
IBinder
根據(jù)官方文檔[譯]:
接口IBinder 是輕量級高性能遠程調(diào)用機制的核心部分。
該接口描述了和遠程對象交互的抽象協(xié)議魂迄,但是通常我們都不會直接實現(xiàn)它粗截,而是繼承自 Binder。
IBinder 接口中關鍵 API 就是 transact()捣炬,與之相對的是 Binder.onTransact() 方法熊昌。其中绽榛,transact 方法將允許你發(fā)送一個調(diào)用到 IBinder 對象;Binder.onTransact()方法用以接收并處理調(diào)用婿屹。transact方法是一個同步方法灭美,它會一直等到onTransact處理完成返回之后,才會返回昂利。
通過 transact() 發(fā)送的數(shù)據(jù)是 Parcel届腐,本質(zhì)上,Parcel是一般的緩沖區(qū)蜂奸,持有內(nèi)容以及內(nèi)容元數(shù)據(jù)犁苏,而這些元數(shù)據(jù)被用來管理緩沖區(qū)中 IBinder 對象的引用。
這種機制確保了窝撵,當一個IBinder 被寫入到Parcel并發(fā)送到另外一個進程中傀顾,然后又從另外一個進程中發(fā)回來時,原來的進程能收到同樣的IBinder對象碌奉。這種語法短曾,還允許IBinder、Binder對象使用一個唯一的id(可以作為token或者其他目的)以便進行跨進程管理赐劣。
每個運行的進程中嫉拐,都有一個用于 transaction 的線程池。這些線程池被用來處理所有的來自于其它進程的IPC魁兼。舉個例子婉徘,從進程A向進程B進行IPC,A中的線程阻塞在 transact()當它將事務發(fā)送到進程B 時咐汞。
B中的線程池接收到該事務盖呼,在目標對象上調(diào)用Binder.onTransact(),接著回復一個Parcel作為結(jié)果化撕。收到結(jié)果之后几晤,進程A繼續(xù)執(zhí)行。在效果上植阴,就像是在同一個進程中創(chuàng)建一個線程執(zhí)行蟹瘾。
Binder
根據(jù)官方文檔[譯]:
實現(xiàn)了IBinder接口,是輕量級跨進程訪問機制的核心掠手。對于很多開發(fā)者而言憾朴,不需要直接使用這個類,而是描述好希望的接口喷鸽,然后由 aidl 工具生成合適的 Binder 子類众雷。
關于Binder的進一步解釋,可以參考我的另外一篇文章圖說Android Binder機制
AIDL使用
關于aidl在 android studio 中操作方式,網(wǎng)上教程有很多很多报腔,這里就不再描述具體該怎么在項目中使用了株搔,而是直接上代碼剖淀,代碼中有注釋纯蛾,描述了關鍵步驟。
public interface IRemoteService extends android.os.IInterface {
/**
* Local-side IPC implementation stub class.
*/
//在服務端將實現(xiàn)該類纵隔,并在onTransact中處理客戶端發(fā)送過來的實體
public static abstract class Stub extends android.os.Binder implements com.ugym.server.IRemoteService {
private static final java.lang.String DESCRIPTOR = "com.test.server.IRemoteService";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.ugym.server.IRemoteService interface,
* generating a proxy if needed.
*/
public static com.test.server.IRemoteService asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.test.server.IRemoteService))) {
return ((com.test.server.IRemoteService) iin);
}
//在客戶端將使用的是代理類翻诉,即這個Proxy
return new com.test.server.IRemoteService.Stub.Proxy(obj);
}
@Override
public android.os.IBinder asBinder() {
return this;
}
// 服務端會在 onTransact 中處理來自客戶端的Parcel
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
//根據(jù) code 判斷,客戶端是想調(diào)用哪個方法
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_basicTypes: {
data.enforceInterface(DESCRIPTOR);
int _arg0;
//獲取調(diào)用參數(shù)
_arg0 = data.readInt();
long _arg1;
//獲取調(diào)用參數(shù)
_arg1 = data.readLong();
boolean _arg2;
_arg2 = (0 != data.readInt());
float _arg3;
_arg3 = data.readFloat();
double _arg4;
_arg4 = data.readDouble();
java.lang.String _arg5;
_arg5 = data.readString();
this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
reply.writeNoException();
return true;
}
case TRANSACTION_addUser: {
data.enforceInterface(DESCRIPTOR);
com.test.server.User _arg0;
if ((0 != data.readInt())) {
//獲取調(diào)用參數(shù)
_arg0 = com.test.server.User.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
//該addUser方法就是在服務端自己實現(xiàn)的
this.addUser(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.test.server.IRemoteService {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(anInt);
_data.writeLong(aLong);
_data.writeInt(((aBoolean) ? (1) : (0)));
_data.writeFloat(aFloat);
_data.writeDouble(aDouble);
_data.writeString(aString);
mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
@Override
public void addUser(com.test.server.User user) throws android.os.RemoteException {
//獲取Parcel對象捌刮,調(diào)用參數(shù)
android.os.Parcel _data = android.os.Parcel.obtain();
//獲取Parcel對象碰煌,返回結(jié)果
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((user != null)) {
_data.writeInt(1);
user.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
//客戶端通過 transact 進行遠程調(diào)用
mRemote.transact(Stub.TRANSACTION_addUser, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
//為每個函數(shù)進行編號
static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
//addUser 函數(shù)的編號
static final int TRANSACTION_addUser = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;
// in 表示傳入數(shù)據(jù), out 表示傳出數(shù)據(jù)绅作, inout 表示雙向傳遞芦圾。注意含有 out 時 User 類需要實現(xiàn) readFromParcel() 方法
public void addUser(com.test.server.User user) throws android.os.RemoteException;
}
在服務端做代碼實現(xiàn),進行業(yè)務邏輯處理:
public class RemoteService extends Service {
private IBinder mIBinder = new IRemoteService.Stub() {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public void addUser(User user) throws RemoteException {
Log.d("RemoteService","addUser") ;
}
};
public RemoteService() {
}
@Override
public IBinder onBind(Intent intent) {
try {
mIBinder.linkToDeath(new IBinder.DeathRecipient() {
@Override
public void binderDied() {
}
},0);
} catch (RemoteException e) {
e.printStackTrace();
}
return mIBinder ;
}
}
當進行bindService后俄认,所有映射關系將被建立好个少。最終,客戶端將得到服務端Binder的句柄眯杏,以此夜焦,通過Binder驅(qū)動和服務端通信。
寫在最后
最后岂贩,還是那句話茫经,AIDL 說白了,從上層看萎津,就是一個通信協(xié)議卸伞。協(xié)議,就是規(guī)矩锉屈,就是約定荤傲,就是結(jié)構,就是架構部念。亦如 Http弃酌, 亦如 TCP,亦如IP儡炼。具體體現(xiàn)形式并不重要妓湘,重要的是 思路, 是結(jié)構化乌询。