在第一節 Android使用binder訪問service的方式(一)中我們介紹了使用Messenger
進行IPC通訊,實現了同一個應用程式中的兩個進程之間的通訊,這一節討論如何?不同應用程式間的通訊。
首先我們修改一下上一節的代碼,使用Messenger實現不同應用程式間的通訊,跟第一節中的service相比,這節我們介紹的service是在另外一個程式中,這一點很關鍵。在上一節中,我們可以通過service的類名來綁定service,在這一節中我們是不知道遠程service的類名的,怎麼才能綁定到我們想要的service呢?使用隱試調用即可,我們不指定service的類名,而是指定action和category,然後通過隱試調用去找到遠端service。
用戶端訪問service代碼:
Intent service = new Intent(); service.setAction(Intent.ACTION_MAIN); service.addCategory(Intent.CATEGORY_DEFAULT); this.bindService(service, mSc, Context.BIND_AUTO_CREATE);
server端的工程需要在AndroidManifest.xml中的修改:
<application android:icon="@drawable/ic_launcher"> <service android:name=".RemoteService"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </service> </application>
例子項目在這裡 IPCbetween2appbyMessenger.rar
Messenger通訊有一個缺點,Messenger 的處理函數是單線程的,如果你想增加對多線程的支援請使用AIDL,aidl產生的介面是可以被多線程訪問的,所以你在編碼的時候就要考慮到多線程訪問造成的安全隱患。
aidl 是android為簡化IPC而提供的介面描述語言檔案,形式上它只是個Java介面的定義,其中定義了服務端要暴露給用戶端的方法列表,如下定義:
// IRemoteService.aidlpackage com.ckt.wangxin.remoteservice;// Declare any non-default types here with import statements/** Example service interface */interface IRemoteService { /** Request the process ID of this service, to do evil things with it. */ int getPid(); /** Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString);}
這個aidl就定義了兩個方法。aidl的更新必須是向後相容的,以保證使用它的用戶端可以正常使用服務。
將aidl放在src下的某個包裡面,clean一下代碼,eclipse會自動編譯aidl成java類到R檔案夾下,用戶端就是使用這個java類來與服務端通訊。
服務端同樣需要放置aidl到對應的包裡面,要與用戶端完全一致。
在服務端:
執行個體化 產生的java類的內部類stub,並實現aidl定義的兩個方法。
IRemoteService.Stub mBinder = new IRemoteService.Stub(){ @Override public int getPid() throws RemoteException { return 234; } @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException { // TODO Auto-generated method stub } };
然後將此類從onBind方法中返回給用戶端。
在用戶端:
在onServiceConnected回調方法中獲得IBinder對象,通過aidl產生的asInterface方法將其轉換成aidl產生的最外部那個類。
直接調用aidl產生的最外部類就可以調用遠程介面了。
mService = IRemoteService.Stub.asInterface(service); try { Toast.makeText(RemoteServiceTestActivity.this,"remote service pid is:"+mService.getPid(), Toast.LENGTH_LONG).show(); } catch (RemoteException e) { // TODO Auto-generated catch block e.printStackTrace(); }
此部分的示範代碼 CommunicatThroughAidl.zip