前言
AIDL是什么描孟?還記得好多面試知識點中提到驶睦,應(yīng)用之間的跨進(jìn)程通信有哪些方式,AIDL好幾次被作為正確答案來說匿醒,其實這是大錯特錯场航,其實AIDL就是幫程序員偷懶的封裝類。AIDL只是對Binder和BinderProxy對象進(jìn)行一層分裝廉羔。
Binder和BinderProxy對象的理解
進(jìn)程A在自己程序中new一個Binder對象溉痢,進(jìn)程B可以通過ServiceManager拿到Binder對象的客戶端代理類BinderProxy對象。當(dāng)進(jìn)程B通過調(diào)用BinderProxy的對象來與進(jìn)程A中Binder類進(jìn)行跨進(jìn)程通信憋他,具體怎么調(diào)用的請看下圖:
注意transact方法和onTransact方法的參數(shù)
code:int型孩饼,這個代表這次通信的requestID,這樣子在Binder端就可以根據(jù)requestID調(diào)用對應(yīng)的代碼了举瑰,可以理解為方法名
data:可以理解為方法中的參數(shù)
reply:方法的返回值
flag:這個flag代表Binder通信是否是同步還是異步捣辆,暫時可以忽略蔬螟。我們重點關(guān)注三個此迅。
假如沒有AIDL,一次跨進(jìn)程的調(diào)用的方式是怎么樣子:
我用偽代碼來實現(xiàn)一下旧巾,我們假設(shè)進(jìn)程A把一個整數(shù)2傳遞給進(jìn)程B耸序,進(jìn)程B將這個整數(shù)的平方4,傳遞給進(jìn)程A鲁猩。
進(jìn)程A中客戶端代碼
int getX2result(int x){
int requestID = 1;
BinderProxy mClient = ServiceManager.getService("進(jìn)程B的服務(wù)A")
Parcel data = new Parcel();
data.writeInt(x)
Parcel reply = new Parcel():
mClient.transact(requestID, data,reply,0)//flag設(shè)置成0,調(diào)用這個方法會跨進(jìn)程調(diào)用Binder服務(wù)類中onTransact方法
int result = replay.readInt();
return result
}
進(jìn)程B中服務(wù)端代碼
protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply,
int flags) throws RemoteException {
if(code == 1) {
int x = data.readInt();
reply.writeInt(getX2result(x));
return true;
}
}
int getX2result(int x){
return x*x;
}
寫到這里小編已經(jīng)累死了坎怪,假如一個服務(wù)需要一百個這樣子的方法,我不得累死廓握,所以科技的進(jìn)步的本質(zhì)就是人類偷懶搅窿。有人就發(fā)現(xiàn)了嘁酿,上面的偽代碼好像都很有規(guī)律,能否只提供int getX2result(int x)男应,你就幫我自動生成上面的客戶端和服務(wù)端的代碼闹司。其實AIDL就是這個偷懶的工具。如果大家去看看AIDL生成java類沐飘,里面做的事情就是這樣子游桩。
在native層中使用BBinder和BpBinder,有沒有類似AIDL的工具
可惜沒有只能手動去寫了
更新:其實AIDL可以生成BBinder和BpBinder耐朴,源碼下編譯用Android.bp就可以了借卧。
小結(jié)
所以下次面試,別再說AIDL是跨進(jìn)程通信的方式筛峭,本質(zhì)是對Binder機制的封裝铐刘,謝謝,小編要睡覺了影晓。正確android中跨進(jìn)程通信的方式主要有以下三類:
1.socket通信滨达,應(yīng)用A初始化請求Zygote孵化出新的進(jìn)程
2.匿名共享內(nèi)存,因為Binder不支持圖像這樣子的大數(shù)據(jù)傳輸俯艰,所以用匿名共享內(nèi)存?zhèn)鬏攽?yīng)用界面的圖像到SurfaceFlinger
3.Binder機制捡遍,android系統(tǒng)中到處都是Binder,可以說無Binder無android
彩蛋
手寫AIDL實現(xiàn)[027]十分鐘讓你明白AIDL