生活随笔
收集整理的這篇文章主要介紹了
Android实战技术:深入理解Android的RPC方式与AIDL
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
目錄(?)[-]
Understanding ADIL揭開(kāi)面紗脫去外套本質(zhì)--脫去內(nèi)衣原理和內(nèi)幕不用AIDL來(lái)實(shí)現(xiàn)
Understanding ADIL
AIDL是一個(gè)接口描述文件,用于實(shí)現(xiàn)Android平臺(tái)上面的RPC,aapt在編譯的時(shí)候會(huì)自動(dòng)根據(jù)規(guī)則生成用于IPC的接口和對(duì)象,而作為使用者只需要:1.在服務(wù)端Service實(shí)現(xiàn)接口;2. 在客戶(hù)端bindService,onServiceConnected時(shí)獲取接口對(duì)象。這里的接口都是AIDL中描述的接口,其他的細(xì)節(jié)則在由AIDL生成的同名源碼文件中。
揭開(kāi)面紗
可以看一下gen文件夾下生成的與AIDL文件同名的源碼文件,這個(gè)文件看似很復(fù)雜,通過(guò)這個(gè)文件來(lái)可以了解AIDL的本質(zhì),這里面有一個(gè)接口,里面在的方法就是AIDL文件中所定義的方法;還有一個(gè)Stub,這個(gè)就是我們要在Service端實(shí)現(xiàn)的基類(lèi);還有一個(gè)Proxy。它們之間的關(guān)系是這們的。
從使用者的角度來(lái)瀏覽這個(gè)源碼文件:它的最外層是一個(gè)與AIDL同名的接口,這里是PrinterInterface,其內(nèi)有一個(gè)接受String的方法print。Client端使用時(shí)是用PrinterInterface.Stub.asInterface,可以看到這個(gè)方法會(huì)返回一個(gè)實(shí)現(xiàn)了PrinterInterface接口的對(duì)象。另外就是Server端會(huì)讓Service實(shí)現(xiàn)PrinterInterface.Stub,其實(shí)是實(shí)現(xiàn)PrinterInterface,因?yàn)镾tub也繼承自PrinterInterface。所以,貌似的時(shí)序是這樣的:客戶(hù)端獲取了一個(gè)實(shí)現(xiàn)了PrinterInterface接口的對(duì)象,而服務(wù)端要實(shí)現(xiàn)此接口。
但是這樣看起來(lái)還是有些亂,我們需要繼續(xù)脫去它的衣服!(天熱啊,得繼續(xù)脫啊!)
脫去外套
因?yàn)橛葾IDL生成的文件無(wú)法編譯,所以我們創(chuàng)建一個(gè)一模一樣的文件來(lái)進(jìn)行,以方便我們對(duì)其進(jìn)行編輯和改動(dòng)。我們分別在獲取IBinder對(duì)象時(shí),Stub的相關(guān)方法里和Proxy的相關(guān)方法里加上日志語(yǔ)句,以跟蹤程序的行為:
通過(guò)跟蹤調(diào)試可以得到以下結(jié)論:
當(dāng)通訊的雙方在同一個(gè)進(jìn)程中時(shí),onServiceConnected傳回的對(duì)象是Service.onBind()所返回的對(duì)象;但如果是跨進(jìn)程時(shí),則其返回的是一個(gè)BinderProxy對(duì)象。所以,可以看到在AIDL生成的類(lèi)中會(huì)有這樣的判斷:
[java]?view plain
?copy ?print?
if?(((iin?!=?null)?&&?(iin?instanceof?MyPrinterInterface)))?{?? ????Log.e(TAG,?"we?have?local?interface,?so?we?use?it");?? ????????return?((MyPrinterInterface)?iin);?? }?? 這實(shí)際上就是判斷此通訊是在同一進(jìn)程中,還是跨進(jìn)程,因?yàn)橥贿M(jìn)程傳回的對(duì)象是Service.onBind()所返回的對(duì)象,而此對(duì)象必然實(shí)現(xiàn)了接口(要不然搞毛啊!)。所以,如果僅是在同一個(gè)進(jìn)程之中,不會(huì)走Binder進(jìn)程IPC,而是直接返回Service所提供的對(duì)象,直接調(diào)用其方法,因此也就不會(huì)有對(duì)象必須Parcelable的限制!
也就是說(shuō),當(dāng)在同一個(gè)進(jìn)程中時(shí)AIDL實(shí)際上變成了這樣的:
也就是說(shuō)它是直接返回了Service.onBind()的對(duì)象,這其實(shí)跟前面提到的第一種方式:直接實(shí)現(xiàn)Binder對(duì)象的方式是一樣一樣的,其他的代碼全是多余的。因此,如前面建議的,如果僅是在同一個(gè)進(jìn)程中,就直接使用Binder就好了,沒(méi)有必要?jiǎng)?chuàng)建AIDL文件。
當(dāng)在不同的進(jìn)程中時(shí),客戶(hù)端Stub.asInterface會(huì)返回一個(gè)Stub.Proxy對(duì)象,調(diào)用其上的print方法。而服務(wù)端僅會(huì)執(zhí)行Stub.onTransact()方法,然后就調(diào)到Service的print方法了。
當(dāng)跨進(jìn)程的時(shí)候,就要使用Binder對(duì)象的IPC相關(guān)的方法和機(jī)制??蛻?hù)端需要實(shí)現(xiàn)Binder.transact()方法來(lái)執(zhí)行遠(yuǎn)程的一個(gè)方法,這是給客戶(hù)端來(lái)使用;而服務(wù)端則需要實(shí)現(xiàn)Binder.onTransact()來(lái)響應(yīng)客戶(hù)端所請(qǐng)求的方法。對(duì)于上層使用者來(lái)說(shuō),用transact()把函數(shù)的信息(參數(shù),標(biāo)識(shí)和開(kāi)關(guān))發(fā)送出去,剩下的就是Binder的工作了,內(nèi)部還有大量的細(xì)節(jié),但是最終會(huì)調(diào)用到服務(wù)端Binder的onTransact()方法,這里識(shí)別出函數(shù)的標(biāo)識(shí),然后調(diào)用具體的實(shí)現(xiàn),再傳回返回值,這樣一個(gè)IPC的函數(shù)調(diào)用就完成了。
當(dāng)跨進(jìn)程時(shí),僅以下代碼是各自所必須的,去掉了無(wú)關(guān)代碼:
Server service: [java]?view plain
?copy ?print?
public?class?MyServerService?extends?Service?{?? ????private?static?final?String?TAG?=?"MyServerService";?? ????private?Handler?mHandler?=?new?Handler();?? ????@Override?? ????public?IBinder?onBind(Intent?intent)?{?? ????????return?mBinder;?? ????}?? ?????? ????private?MyPrinterInterfaceStub?mBinder?=?new?MyPrinterInterfaceStub()?{?? ????????@Override?? ????????public?void?print(String?msg)?throws?RemoteException?{?? ????????????MyServerService.this.print(msg);?? ????????}?? ????};?? ?????? ????public?void?print(String?msg)?{?? ????????try?{?? ????????????Log.e(TAG,?"Preparing?printer...");?? ????????????Thread.sleep(1000);?? ????????????Log.e(TAG,?"Connecting?printer...");?? ????????????Thread.sleep(1000);?? ????????????Log.e(TAG,?"Printing....?"?+?msg);?? ????????????Thread.sleep(1000);?? ????????????Log.e(TAG,?"Done");?? ????????}?catch?(InterruptedException?e)?{?? ????????}?? ????????mHandler.post(new?Runnable()?{?? ????????????@Override?? ????????????public?void?run()?{?? ????????????????Toast.makeText(MyServerService.this,?"MyServerService?Printing?is?done.",?Toast.LENGTH_LONG).show();?? ????????????}?? ????????});?? ????}?? }?? serer side interface definition:
[java]?view plain
?copy ?print?
public?interface?MyPrinterInterface?extends?android.os.IInterface?{?? ????public?void?print(String?msg)?throws?android.os.RemoteException;?? }?? ?? ?? abstract?class?MyPrinterInterfaceStub?extends?Binder?implements?MyPrinterInterface?{?? ????private?static?final?String?DESCRIPTOR?=?"MyPrinterInterface";?? ????private?static?final?String?TAG?=?"MyPrinterInterfaceStub";?? ?? ?? ????public?MyPrinterInterfaceStub()?{?? ????????attachInterface(this,?DESCRIPTOR);?? ????}?? ?? ?? ????@Override?? ????public?IBinder?asBinder()?{?? ????????return?this;?? ????}?? ?? ?? ????@Override?? ????public?boolean?onTransact(int?code,?Parcel?data,?Parcel?reply,?int?flags)?? ????????????throws?android.os.RemoteException?{?? ????????Log.e(TAG,?"onTransact,?code?is?"?+?code);?? ????????switch?(code)?{?? ????????case?INTERFACE_TRANSACTION:?{?? ????????????Log.e(TAG,?"onTransact,?code?is?"?+?code?+?",?when?this?happens");?? ????????????reply.writeString(DESCRIPTOR);?? ????????????return?true;?? ????????}?? ????????case?TRANSACTION_print:?{?? ????????????data.enforceInterface(DESCRIPTOR);?? ????????????String?_arg0;?? ????????????_arg0?=?data.readString();?? ????????????Log.e(TAG,?"ontransact,?arg?is?"?+?_arg0?+?",?when?this?happened?");?? ????????????this.print(_arg0);?? ????????????reply.writeNoException();?? ????????????return?true;?? ????????}?? ????????}?? ????????return?super.onTransact(code,?data,?reply,?flags);?? ????}?? ?????? ????static?final?int?TRANSACTION_print?=?(IBinder.FIRST_CALL_TRANSACTION?+?0);?? }?? Client activity:
[java]?view plain
?copy ?print?
public?class?AnotherMyClientActivity?extends?Activity?{?? ????private?static?final?String?TAG?=?"MyClientActivity";?? ????MyPrinterInterface?mService;?? ?? ?? ????@Override?? ????protected?void?onCreate(Bundle?savedInstanceState)?{?? ????????super.onCreate(savedInstanceState);?? ????????setContentView(R.layout.printer_activity);?? ????????setTitle("My?interface?another?client?Activity");?? ????????((Button)?findViewById(R.id.play)).setText("Print?via?my?interface");?? ????}?? ?? ?? ????@Override?? ????protected?void?onStart()?{?? ????????super.onStart();?? ????????doBindService();?? ????}?? ?? ?? ????private?void?doBindService()?{?? ????????Intent?intent?=?new?Intent();?? ????????intent.setClassName("com.example.effectiveandroid",?"com.example.effectiveandroid.MyServerService");?? ????????bindService(intent,?mConnection,?Context.BIND_AUTO_CREATE);?? ????}?? ?? ?? ????@Override?? ????protected?void?onStop()?{?? ????????super.onStop();?? ????????doUnbindService();?? ????}?? ?? ?? ????private?void?doUnbindService()?{?? ????????if?(mService?!=?null)?{?? ????????????unbindService(mConnection);?? ????????}?? ????}?? ?????? ????public?void?onButtonClick(View?v)?{?? ????????if?(mService?==?null)?{?? ????????????Log.e(TAG,?"what?the?fucl?service?is?not?ready");?? ????????????return;?? ????????}?? ????????try?{?? ????????????mService.print("In?another?application,?create?a?client?based?on?user?defined?IPC?interfaces");?? ????????}?catch?(RemoteException?e)?{?? ????????????e.printStackTrace();?? ????????}?? ????}?? ?????? ????private?ServiceConnection?mConnection?=?new?ServiceConnection()?{?? ????????@Override?? ????????public?void?onServiceConnected(ComponentName?className,?IBinder?service)?{?? ????????????Log.e(TAG,?"on?service?connected,?service?obj?"?+?service);?? ????????????mService?=?MyPrinterInterface.Stub.asInterface(service);?? ????????}?? ?? ?? ????????@Override?? ????????public?void?onServiceDisconnected(ComponentName?arg0)?{?? ????????????mService?=?null;?? ????????}?? ????};?? }?? client side interface definiition:
[java]?view plain
?copy ?print?
public?interface?MyPrinterInterface?extends?android.os.IInterface?{?? ????public?void?print(String?msg)?throws?android.os.RemoteException;?? ?????? ????public?abstract?class?Stub?extends?Binder?implements?MyPrinterInterface?{?? ????????private?static?final?String?DESCRIPTOR?=?"MyPrinterInterface";?? ????????private?static?final?String?TAG?=?"MyPrinterInterface.Stub";?? ?????????? ????????public?Stub()?{?? ????????????attachInterface(this,?DESCRIPTOR);?? ????????}?? ?????????? ????????public?static?MyPrinterInterface?asInterface(IBinder?obj)?{?? ????????????if?((obj?==?null))?{?? ????????????????return?null;?? ????????????}?? ?? ?? ????????????Log.e(TAG,?"we?are?talking?to?a?remote?one,?we?must?use?a?proxy?object?to?wrapper?binder");?? ????????????return?new?Stub.Proxy(obj);?? ????????}?? ?????????? ????????static?final?int?TRANSACTION_print?=?(IBinder.FIRST_CALL_TRANSACTION?+?0);?? ?????????? ????????private?static?class?Proxy?implements?MyPrinterInterface?{?? ????????????private?IBinder?mRemote;?? ?????????????? ????????????Proxy(IBinder?remote)?{?? ????????????????mRemote?=?remote;?? ????????????}?? ?????????????? ????????????@Override?? ????????????public?IBinder?asBinder()?{?? ????????????????return?mRemote;?? ????????????}?? ?????????????? ????????????public?String?getInterfaceDescriptor()?{?? ????????????????return?DESCRIPTOR;?? ????????????}?? ?????????????? ????????????@Override?? ????????????public?void?print(String?msg)?throws?android.os.RemoteException?{?? ????????????????Parcel?_data?=?Parcel.obtain();?? ????????????????Parcel?_reply?=?Parcel.obtain();?? ????????????????try?{?? ????????????????????_data.writeInterfaceToken(DESCRIPTOR);?? ????????????????????_data.writeString(msg);?? ????????????????????mRemote.transact(Stub.TRANSACTION_print,?_data,?_reply,?0);?? ????????????????????Log.e(TAG,?"lalalala,?let?us?passing?the?parameters?and?calling?the?message");?? ????????????????????_reply.readException();?? ????????????????}?finally?{?? ????????????????????_reply.recycle();?? ????????????????????_data.recycle();?? ????????????????}?? ????????????}?? ????????}?? ????}?? }?? 本質(zhì)--脫去內(nèi)衣
其實(shí)AIDL的作用就是對(duì)Binder的二個(gè)方法:Binder.transact()和Binder.onTransact()進(jìn)行封裝,以供Client端和Server端進(jìn)行使用。因?yàn)閷?shí)現(xiàn)transact()和onTransact()方法的方式基本上是相同的,所以就可以用模板來(lái)生成具體的代碼。理論上講只需要為Client端生成transact()相關(guān)代碼,為服務(wù)端生成onTransact()代碼即可,但因?yàn)楣ぞ邿o(wú)法準(zhǔn)確的確定某一個(gè)應(yīng)用到底是Client端還是Server端,所以它就生成所有的代碼,放在一個(gè)文件中。這就是你看到的自動(dòng)生成的文件。
還需要注意的一點(diǎn)是Client端的Proxy是組合Binder對(duì)象,調(diào)用其transact()方法;而服務(wù)端必須繼承Binder對(duì)象,覆寫(xiě)onTransact()方法。為蝦米呢?因?yàn)镃lient是主動(dòng)發(fā)起IPC函數(shù)Call,所以它可以直接調(diào)用Binder的方法來(lái)進(jìn)行IPC。而Server是被動(dòng)的,是要接收進(jìn)來(lái)的IPC call,但Service自己無(wú)法得知啥時(shí)候Call會(huì)來(lái),因此必須實(shí)現(xiàn)回調(diào)(onTransact())給Binder,以讓Binder在有IPC Call進(jìn)來(lái)的時(shí)候告訴Service。
原理和內(nèi)幕
AIDL的角色是實(shí)現(xiàn)Android平臺(tái)上面的RPC(Remote Procedure Call)也即遠(yuǎn)程例程調(diào)用。RPC是IPC中的一種,但是它是以調(diào)用在本地或者另一個(gè)進(jìn)程,甚至是另一個(gè)主機(jī)上的方法的機(jī)制。RPC的目的就是可以讓程序不用擔(dān)心方法具體是在哪個(gè)進(jìn)程里面或者哪以機(jī)器上面,就像正常的本地方法那樣去調(diào)用即可,RPC機(jī)制會(huì)處理所有的具體細(xì)節(jié)。RPC一般用IDL(Interface Definition Language)來(lái)描述,實(shí)現(xiàn)則要看具體的平臺(tái)和語(yǔ)言??梢詤⒖糤ikipedia來(lái)看RPC?和IDL?的更多信息。
AIDL提供Android平臺(tái)的RPC的支持:開(kāi)發(fā)者僅需要要定義AIDL,做一些相關(guān)的適配工作,然后就可以使用這些方法了,不用具體關(guān)心接口描述的方法空究竟是在同一個(gè)進(jìn)程中還是在其他的進(jìn)程中。這些RPC實(shí)現(xiàn)的細(xì)節(jié)由Binder和系統(tǒng)來(lái)處理。
Binder RPC的流程:<Binder RPC sequence>
可以看到這個(gè)流程是一個(gè)標(biāo)準(zhǔn)的RPC流程。
不用AIDL來(lái)實(shí)現(xiàn)
知道了AIDL的本質(zhì)后,就可以不用AIDL來(lái)實(shí)現(xiàn)IPC,雖然AIDL簡(jiǎn)單方便,但是它卻非常不容易理解,而且代碼有冗余(服務(wù)端并不需要為Client準(zhǔn)備的對(duì)象,反之亦然)。
所以我們可以自已實(shí)現(xiàn):
Server interface:
[java]?view plain
?copy ?print?
public?interface?ServerPrinterInterface?{?? ????public?void?print(String?msg)?throws?android.os.RemoteException;?? }?? ?? ?? abstract?class?MyPrinterInterfaceStub?extends?Binder?implements?ServerPrinterInterface,?IInterface?{?? ????private?static?final?String?DESCRIPTOR?=?"MyPrinterInterface";?? ????static?final?int?TRANSACTION_print?=?(IBinder.FIRST_CALL_TRANSACTION?+?0);?? ????private?static?final?String?TAG?=?"MyPrinterInterfaceStub";?? ?? ?? ????public?MyPrinterInterfaceStub()?{?? ????????attachInterface(this,?DESCRIPTOR);?? ????}?? ?? ?? ????@Override?? ????public?IBinder?asBinder()?{?? ????????return?this;?? ????}?? ?? ?? ????@Override?? ????public?boolean?onTransact(int?code,?Parcel?data,?Parcel?reply,?int?flags)?? ????????????throws?android.os.RemoteException?{?? ????????Log.e(TAG,?"onTransact,?code?is?"?+?code);?? ????????switch?(code)?{?? ????????case?INTERFACE_TRANSACTION:?{?? ????????????Log.e(TAG,?"onTransact,?code?is?"?+?code?+?",?when?this?happens");?? ????????????reply.writeString(DESCRIPTOR);?? ????????????return?true;?? ????????}?? ????????case?TRANSACTION_print:?{?? ????????????data.enforceInterface(DESCRIPTOR);?? ????????????String?_arg0;?? ????????????_arg0?=?data.readString();?? ????????????Log.e(TAG,?"ontransact,?arg?is?"?+?_arg0?+?",?when?this?happened?");?? ????????????this.print(_arg0);?? ????????????reply.writeNoException();?? ????????????return?true;?? ????????}?? ????????}?? ????????return?super.onTransact(code,?data,?reply,?flags);?? ????}?? }?? service:
[java]?view plain
?copy ?print?
public?class?MyServerService?extends?Service?{?? ????private?static?final?String?TAG?=?"MyServerService";?? ????private?Handler?mHandler?=?new?Handler();?? ????@Override?? ????public?IBinder?onBind(Intent?intent)?{?? ????????return?mBinder;?? ????}?? ?????? ????private?MyPrinterInterfaceStub?mBinder?=?new?MyPrinterInterfaceStub()?{?? ????????@Override?? ????????public?void?print(String?msg)?throws?RemoteException?{?? ????????????MyServerService.this.print(msg);?? ????????}?? ????};?? ?????? ????public?void?print(String?msg)?{?? ????????try?{?? ????????????Log.e(TAG,?"Preparing?printer...");?? ????????????Thread.sleep(1000);?? ????????????Log.e(TAG,?"Connecting?printer...");?? ????????????Thread.sleep(1000);?? ????????????Log.e(TAG,?"Printing....?"?+?msg);?? ????????????Thread.sleep(1000);?? ????????????Log.e(TAG,?"Done");?? ????????}?catch?(InterruptedException?e)?{?? ????????}?? ????????mHandler.post(new?Runnable()?{?? ????????????@Override?? ????????????public?void?run()?{?? ????????????????Toast.makeText(MyServerService.this,?"MyServerService?Printing?is?done.",?Toast.LENGTH_LONG).show();?? ????????????}?? ????????});?? ????}?? }?? client interface:
[java]?view plain
?copy ?print?
public?interface?ClientPrinterInterface?{?? ????public?void?print(String?msg)?throws?android.os.RemoteException;?? }?? ?? ?? class?MyPrinterInterfaceProxy?implements?ClientPrinterInterface?{?? ????private?static?final?String?DESCRIPTOR?=?"MyPrinterInterface";?? ????static?final?int?TRANSACTION_print?=?(IBinder.FIRST_CALL_TRANSACTION?+?0);?? ????private?static?final?String?TAG?=?"MyPrinterInterfaceProxy";?? ????private?IBinder?mRemote;?? ?? ?? ????MyPrinterInterfaceProxy(IBinder?remote)?{?? ????????mRemote?=?remote;?? ????}?? ?? ?? ????@Override?? ????public?void?print(String?msg)?throws?android.os.RemoteException?{?? ????????Parcel?_data?=?Parcel.obtain();?? ????????Parcel?_reply?=?Parcel.obtain();?? ????????try?{?? ????????????_data.writeInterfaceToken(DESCRIPTOR);?? ????????????_data.writeString(msg);?? ????????????mRemote.transact(TRANSACTION_print,?_data,?_reply,?0);?? ????????????Log.e(TAG,?"lalalala,?let?us?passing?the?parameters?and?calling?the?message");?? ????????????_reply.readException();?? ????????}?finally?{?? ????????????_reply.recycle();?? ????????????_data.recycle();?? ????????}?? ????}?? }?? client activity:
[java]?view plain
?copy ?print?
public?class?AnotherMyClientActivity?extends?Activity?{?? ????private?static?final?String?TAG?=?"MyClientActivity";?? ????ClientPrinterInterface?mService;?? ?? ?? ????@Override?? ????protected?void?onCreate(Bundle?savedInstanceState)?{?? ????????super.onCreate(savedInstanceState);?? ????????setContentView(R.layout.printer_activity);?? ????????setTitle("My?interface?another?client?Activity");?? ????????((Button)?findViewById(R.id.play)).setText("Print?via?my?interface");?? ????}?? ?? ?? ????@Override?? ????protected?void?onStart()?{?? ????????super.onStart();?? ????????doBindService();?? ????}?? ?? ?? ????private?void?doBindService()?{?? ????????Intent?intent?=?new?Intent();?? ????????intent.setClassName("com.example.effectiveandroid",?"com.example.effectiveandroid.MyServerService");?? ????????bindService(intent,?mConnection,?Context.BIND_AUTO_CREATE);?? ????}?? ?? ?? ????@Override?? ????protected?void?onStop()?{?? ????????super.onStop();?? ????????doUnbindService();?? ????}?? ?? ?? ????private?void?doUnbindService()?{?? ????????if?(mService?!=?null)?{?? ????????????unbindService(mConnection);?? ????????}?? ????}?? ?????? ????public?void?onButtonClick(View?v)?{?? ????????if?(mService?==?null)?{?? ????????????Log.e(TAG,?"what?the?fucl?service?is?not?ready");?? ????????????return;?? ????????}?? ????????try?{?? ????????????mService.print("In?another?application,?create?a?client?based?on?user?defined?IPC?interfaces");?? ????????}?catch?(RemoteException?e)?{?? ????????????e.printStackTrace();?? ????????}?? ????}?? ?????? ????private?ServiceConnection?mConnection?=?new?ServiceConnection()?{?? ????????@Override?? ????????public?void?onServiceConnected(ComponentName?className,?IBinder?service)?{?? ????????????Log.e(TAG,?"on?service?connected,?service?obj?"?+?service);?? ????????????mService?=?new?MyPrinterInterfaceProxy(service);?? ????????}?? ?? ?? ????????@Override?? ????????public?void?onServiceDisconnected(ComponentName?arg0)?{?? ????????????mService?=?null;?? ????????}?? ????};?? }?? 從這里可以看到不使用AIDL有二個(gè)好處:
1. 自己實(shí)現(xiàn)還有一個(gè)好處就是可以隨意設(shè)計(jì)包名。如果使用AIDL則Client端的AIDL文件所在package必須與Server端的AIDL的package完全一致,否則會(huì)找不到service,Client端會(huì)有異常。但如果自己實(shí)現(xiàn)接口,就沒(méi)有此限制,可以把接口文件放在任何的package內(nèi)。
為什么呢?因?yàn)锳IDL生成的Stub和Proxy用的標(biāo)識(shí)DESCRIPTOR加入了package的名字。而如果自己實(shí)現(xiàn)接口,可以任意的寫(xiě)這個(gè)DESCRIPTOR。
2. 接口的名字實(shí)際上無(wú)所謂,更進(jìn)一步,其實(shí)方法的簽名也可以不完全一致。因?yàn)檫@二個(gè)接口,一個(gè)是在Client端,另一個(gè)是在Server端。它們之間的聯(lián)系是間接的通過(guò)Binder對(duì)象實(shí)現(xiàn)的。只要Binder對(duì)象的transact和onTransact二個(gè)方法能找到相應(yīng)的接口方法即可。 關(guān)鍵的通訊標(biāo)識(shí)和方法標(biāo)識(shí)
從上面的例子可以看出客戶(hù)Proxy的transact,和服務(wù)Stub的onTransact使用二個(gè)標(biāo)識(shí)來(lái)識(shí)別對(duì)方:一個(gè)是DESCRIPTOR,這個(gè)是標(biāo)識(shí)Binder的Token,也就是說(shuō)是標(biāo)識(shí)服務(wù)端和客戶(hù)端;方法的標(biāo)識(shí)就是TRANSACTION_print,是用來(lái)標(biāo)識(shí)調(diào)用的是哪個(gè)方法。這個(gè)理解起來(lái)也不是很難,就好比打電話(huà),先要通過(guò)通訊的標(biāo)識(shí)電話(huà)號(hào)碼找到相應(yīng)的人,然后跟人說(shuō)的時(shí)候要告訴他是哪件事(哪個(gè)方法)。
接下來(lái)可以二個(gè)方面來(lái)進(jìn)行深入的研究:
1. bindService是如何獲得Binder對(duì)象的(無(wú)論是本地時(shí)Service的實(shí)現(xiàn),還是遠(yuǎn)程時(shí)的BinderProxy),或者說(shuō)是如何查詢(xún)到Binder對(duì)象。
這是ServiceConnection.onServiceConnected的調(diào)用棧:
2. Binder.transact()和Binder.onTransact()的細(xì)節(jié),這也是具體Binder IPC機(jī)制的細(xì)節(jié)。
原文地址:?http://blog.csdn.net/hitlion2008/article/details/9824009
總結(jié)
以上是生活随笔為你收集整理的Android实战技术:深入理解Android的RPC方式与AIDL的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。