(1) 服務器端新建AIDL文件定義接口
在服務器端的src目錄下新建以.aidl為后綴的文件,在這個文件中定義一個接口,聲明服務器端和客戶端交互的api,語法跟普通java接口聲明一樣,可以添加中英文注釋。不同的是
a. 除了Java基本數據類型 (int, long, char, boolean等)、String、CharSequence、List、Map外,其他復雜類型都需要顯式import(包括其他AIDL定義的接口),即便復雜類型在同一個包內定義。
b. 支持泛型實例化的List,如List<String>;不支持泛型實例化的Map,如Map<String, String>。對於List為參數接收者接收到的始終是ArrayList;對於Map為參數接收者接收到的始終是HashMap。
c. interface和函數都不能帶訪問權限修飾符。
d. 接口內只允許定義方法,不允許定義靜態屬性。
我們定義MyAIDLInterface.aidl文件如下
package com.trinea.android.demo; interface MyAIDLInterface { int getCount(); void setCount(int count); }
聲明兩個接口在后面供客戶端調用。保存文件,編譯后,Sdk工具在gen目錄下相同子目錄中自動生成同名的以.java為后綴的文件,這里文件名為MyAIDLInterface.java。
(2) 自動生成的同名java文件解析
MyAIDLInterface.java為Sdk工具自動生成,內容如下

/* * This file is auto-generated. DO NOT MODIFY. * Original file: D:\\Eclipse\\AndroidDemo\\MapDemo\\src\\com\\trinea\\android\\demo\\MyAIDLInterface.aidl */ package com.trinea.android.demo; public interface MyAIDLInterface extends android.os.IInterface { /** Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements com.trinea.android.demo.MyAIDLInterface { private static final java.lang.String DESCRIPTOR = "com.trinea.android.demo.MyAIDLInterface"; /** Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an com.trinea.android.demo.MyAIDLInterface interface, * generating a proxy if needed. */ public static com.trinea.android.demo.MyAIDLInterface asInterface(android.os.IBinder obj) { if ((obj==null)) { return null; } android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR); if (((iin!=null)&&(iin instanceof com.trinea.android.demo.MyAIDLInterface))) { return ((com.trinea.android.demo.MyAIDLInterface)iin); } return new com.trinea.android.demo.MyAIDLInterface.Stub.Proxy(obj); } public android.os.IBinder asBinder() { return this; } @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_getCount: { data.enforceInterface(DESCRIPTOR); int _result = this.getCount(); reply.writeNoException(); reply.writeInt(_result); return true; } case TRANSACTION_setCount: { data.enforceInterface(DESCRIPTOR); int _arg0; _arg0 = data.readInt(); this.setCount(_arg0); reply.writeNoException(); return true; } } return super.onTransact(code, data, reply, flags); } private static class Proxy implements com.trinea.android.demo.MyAIDLInterface { private android.os.IBinder mRemote; Proxy(android.os.IBinder remote) { mRemote = remote; } public android.os.IBinder asBinder() { return mRemote; } public java.lang.String getInterfaceDescriptor() { return DESCRIPTOR; } public int getCount() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); int _result; try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_getCount, _data, _reply, 0); _reply.readException(); _result = _reply.readInt(); } finally { _reply.recycle(); _data.recycle(); } return _result; } public void setCount(int count) 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(count); mRemote.transact(Stub.TRANSACTION_setCount, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } } static final int TRANSACTION_getCount = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_setCount = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); } public int getCount() throws android.os.RemoteException; public void setCount(int count) throws android.os.RemoteException; }
其中有幾個主要的部分:
a. 抽象類Stub,繼承Binder實現自定義接口,作用同進程內通信服務中自定義的Binder,客戶端通過它對服務進行調用。
b. 靜態類Proxy,實現自定義接口,代理模式接收對Stub的調用。
(3) 服務器端定義服務

package com.trinea.android.demo; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.RemoteException; import android.widget.Toast; public class MyAIDLService extends Service { private int mCount; private MyAIDLInterface.Stub myBinder = new MyAIDLInterface.Stub() { @Override public void setCount(int count) throws RemoteException { mCount = count; } @Override public int getCount() throws RemoteException { return mCount; } }; @Override public void onCreate() { mCount = 0; Toast.makeText(this, "Service onCreate", Toast.LENGTH_SHORT).show(); super.onCreate(); } @Override public void onDestroy() { Toast.makeText(this, "Service onDestroy", Toast.LENGTH_SHORT).show(); super.onDestroy(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Toast.makeText(this, Integer.toString(mCount), Toast.LENGTH_SHORT).show(); return super.onStartCommand(intent, flags, startId); } public int getCount() { return mCount; } /** * 服務被綁定時調用 * 返回值用於讓調用者和服務通信,傳入ServiceConnection的public void onServiceConnected(ComponentName name, IBinder service)函數第二個參數 */ @Override public IBinder onBind(Intent intent) { return myBinder; } }
AndroidManifest.xml中注冊服務
<service android:name=".MyAIDLService"> <intent-filter> <action android:name="com.trinea.android.demo.remote.MyAIDLServiceAction" /> </intent-filter> </service>
其中的action name用於后面客戶端調用時匹配
客戶端(代碼見AndroidAidlClient@GoogleCode):
服務器端目錄結構:,客戶端目錄結構:
ERROR/AndroidRuntime(2104): java.lang.SecurityException: Binder invocation to an incorrect interface。后發現是因為服務器端和客戶端aidl文件的包名不同導致生成的java文件不同。

private MyAIDLInterface binder = null; private Intent myAIDLServiceIntent; private ServiceConnection con = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { } @Override public void onServiceConnected(ComponentName name, IBinder service) { binder = MyAIDLInterface.Stub.asInterface(service); } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.client); boundAIDLServiceBtn = (Button)findViewById(R.id.boundAIDLService); myAIDLServiceIntent = new Intent("com.trinea.android.demo.remote.MyAIDLServiceAction"); boundAIDLServiceBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { boolean result = bindService(myAIDLServiceIntent, con, Context.BIND_AUTO_CREATE); if (!result) { binder = null; Toast.makeText(getApplicationContext(), "服務綁定失敗。", Toast.LENGTH_SHORT).show(); } } }); getBoundAIDLServiceProBtn = (Button)findViewById(R.id.getBoundAIDLServicePro); getBoundAIDLServiceProBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { try { if (binder != null) { Toast.makeText(getApplicationContext(), "Service count:" + binder.getCount(), Toast.LENGTH_SHORT).show(); } else { Toast.makeText(getApplicationContext(), "請先綁定服務。", Toast.LENGTH_SHORT).show(); } } catch (RemoteException e) { e.printStackTrace(); } } }); unboundAIDLServiceBtn = (Button)findViewById(R.id.unboundAIDLService); unboundAIDLServiceBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (binder != null) { unbindService(con); binder = null; } } }); }
上面的三個按鈕boundAIDLServiceBtn、getBoundAIDLServiceProBtn、unboundAIDLServiceBtn分別用於綁定服務、得到服務中屬性值、解除綁定服務。
從上面可以看出我們先定義ServiceConnection對象用於和服務器通信,在onServiceConnected函數中通過MyAIDLInterface.Stub.asInterface(service)返回用戶定義的接口對象,通過此對象調用遠程接口api。在boundAIDLServiceBtn的onClick函數中綁定服務,在getBoundAIDLServiceProBtn的onClick函數中調用服務的api,在boundAIDLServiceBtn的onClick函數中取消綁定服務,
現在我們運行兩個項目即可,在客戶端綁定服務再獲取服務屬性顯示。
3、生命周期
通過bindService綁定服務,若服務未啟動,會先執行Service的onCreate函數,再執行onBind函數,最后執行ServiceConnection對象的onServiceConnected函數,客戶端可以自動啟動服務。若服務已啟動但尚未綁定,先執行onBind函數,再執行ServiceConnection對象的onServiceConnected函數。若服務已綁定成功,則直接返回。這里不會自動調用onStartCommand函數。
通過unbindService解除綁定服務,若已綁定成功,會先執行Service的onUnbind函數,再執行onDestroy函數,注意這里不會執行ServiceConnection對象的onServiceDisconnected函數,因為該函數是在服務所在進程被kill或是crash時被調用。