本文提供了一个关于AIDL使用的简单易懂的例子,分为客户端和服务端两部分,分别为客户端和服务端新建一个eclipse工程,实现了从客户端向服务端发送请求,服务端打印log的功能。

我的理解: 进程间的通信 ,让服务器作出反应(大概就是这个意思)

 

客户端和服务端的源码结构如下:


注意,由于客户端和服务端的aidl文件所在包名必须一样,而两个包名一样的程序在安装时会产生冲突,所以这里用了一个技巧,在客户端工程的AndroidManifest.xml里把包名指定为com.styleflying,所以大家就会看到gen目录下的R.java所在的包是com.styleflying而不是com.styleflying.AIDL

 

正文

现在客户端和服务端工程分别新建一个aidl接口,所在包和文件名必须一样。两个aidl接口是一样的,内容如下:

 


[java]  view plain copy

1. package com.styleflying.AIDL;  
2. interface mInterface{  
3. void invokTest();  
4. }


自动编译生成.java文件如下:


[java]  view plain copy

1. /*
2.  * This file is auto-generated.  DO NOT MODIFY.
3.  * Original file: G://workspace//AidlDemo_client//src//com//styleflying//AIDL//mInterface.aidl
4.  */  
5. package com.styleflying.AIDL;  
6. public interface mInterface extends android.os.IInterface  
7. {  
8. /** Local-side IPC implementation stub class. */  
9. public static abstract class Stub extends android.os.Binder implements com.styleflying.AIDL.mInterface  
10.     {  
11. private static final java.lang.String DESCRIPTOR = "com.styleflying.AIDL.mInterface";  
12. /** Construct the stub at attach it to the interface. */  
13. public Stub()  
14.         {  
15. this.attachInterface(this, DESCRIPTOR);  
16.         }  
17. /**
18.          * Cast an IBinder object into an com.styleflying.AIDL.mInterface interface,
19.          * generating a proxy if needed.
20.          */  
21. public static com.styleflying.AIDL.mInterface asInterface(android.os.IBinder obj)  
22.         {  
23. if ((obj==null)) {  
24. return null;  
25.             }  
26.             android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);  
27. if (((iin!=null)&&(iin instanceof com.styleflying.AIDL.mInterface))) {  
28. return ((com.styleflying.AIDL.mInterface)iin);  
29.             }  
30. return new com.styleflying.AIDL.mInterface.Stub.Proxy(obj);  
31.         }  
32. public android.os.IBinder asBinder()  
33.         {  
34. return this;  
35.         }  
36. @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException  
37.         {  
38. switch (code)  
39.             {  
40. case INTERFACE_TRANSACTION:  
41.                 {  
42.                     reply.writeString(DESCRIPTOR);  
43. return true;  
44.                 }  
45. case TRANSACTION_invokTest:  
46.                 {  
47.                     data.enforceInterface(DESCRIPTOR);  
48. this.invokTest();  
49.                     reply.writeNoException();  
50. return true;  
51.                 }  
52.             }  
53. return super.onTransact(code, data, reply, flags);  
54.         }  
55. private static class Proxy implements com.styleflying.AIDL.mInterface  
56.         {  
57. private android.os.IBinder mRemote;  
58.             Proxy(android.os.IBinder remote)  
59.             {  
60.                 mRemote = remote;  
61.             }  
62. public android.os.IBinder asBinder()  
63.             {  
64. return mRemote;  
65.             }  
66. public java.lang.String getInterfaceDescriptor()  
67.             {  
68. return DESCRIPTOR;  
69.             }  
70. public void invokTest() throws android.os.RemoteException  
71.             {  
72.                 android.os.Parcel _data = android.os.Parcel.obtain();  
73.                 android.os.Parcel _reply = android.os.Parcel.obtain();  
74. try {  
75.                     _data.writeInterfaceToken(DESCRIPTOR);  
76. 0);  
77.                     _reply.readException();  
78.                 }  
79. finally {  
80.                     _reply.recycle();  
81.                     _data.recycle();  
82.                 }  
83.             }  
84.         }  
85. static final int TRANSACTION_invokTest = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);  
86.     }  
87. public void invokTest() throws android.os.RemoteException;  
88. }

 

客户端的mAIDLActivity.java如下:


[java]  view plain copy

1. package com.styleflying.AIDL;  
2. import android.app.Activity;  
3. import android.content.ComponentName;  
4. import android.content.Context;  
5. import android.content.Intent;  
6. import android.content.ServiceConnection;  
7. import android.os.Bundle;  
8. import android.os.IBinder;  
9. import android.os.RemoteException;  
10. import android.util.Log;  
11. import android.view.View;  
12. import android.view.View.OnClickListener;  
13. import android.widget.Button;  
14. import android.widget.Toast;  
15. import com.styleflying.R;  
16. public class mAIDLActivity extends Activity {  
17.       
18. private static final String TAG = "AIDLActivity";  
19. private Button btnOk;  
20. private Button btnCancel;  
21. private Button btnCallBack;  
22.       
23. private void Log(String str){  
24. "----------" + str + "----------");  
25.     }  
26.       
27.           
28.     mInterface mService;  
29. private ServiceConnection mConnection = new ServiceConnection(){  
30. public void onServiceConnected(ComponentName className,  
31.                 IBinder service){  
32. "connect service");  
33.             mService = mInterface.Stub.asInterface(service);  
34.         }  
35.           
36. public void onServiceDisconnected(ComponentName className){  
37. "disconnect service");  
38. null;  
39.         }  
40.     };  
41.       
42.       
43.       
44. /** Called when the activity is first created. */  
45. @Override  
46. public void onCreate(Bundle savedInstanceState) {  
47. super.onCreate(savedInstanceState);  
48.             setContentView(R.layout.main);  
49.           
50.         btnOk = (Button)findViewById(R.id.btn_ok);  
51.         btnCancel = (Button)findViewById(R.id.btn_cancel);  
52.         btnCallBack = (Button)findViewById(R.id.btn_callback);  
53.           
54. new OnClickListener(){  
55. public void onClick(View v){  
56. new Bundle();  
57. new Intent("com.styleflying.AIDL.service");  
58.                 intent.putExtras(args);  
59.                 bindService(intent,mConnection,Context.BIND_AUTO_CREATE);  
60.             }  
61.         });  
62.           
63. new OnClickListener(){  
64. public void onClick(View v){  
65.                 unbindService(mConnection);  
66.             }  
67.         });       
68. new OnClickListener(){  
69. public void onClick(View v){  
70. try{  
71. "current Thread id = " + Thread.currentThread().getId());  
72.                     mService.invokTest();  
73.                 }  
74. catch(RemoteException e){  
75.                       
76.                 }  
77.             }  
78.         });  
79.           
80.           
81.     }  
82. }


 

客户端在执行bindService的时候,成功绑定服务之后,会回调mConnection的onServiceConnected(),并且传回了服务端的通信接口IBinder,此IBinder即服务onBind()时返回的IBinder,详见mAIDLService.java。

在onServiceConnected(),客户端成功获取了服务端通信接口,实际上是本地代理对象,该对象存在于客户端进程空间,客户端只和代理对象交互,真正的IPC通信是本地代理对象和服务端的通信。

 

mAIDLService.java如下:


[c-sharp]  view plain copy


1. package com.styleflying.AIDL;  
2. import android.app.Service;  
3. import android.content.Intent;  
4. import android.os.IBinder;  
5. import android.os.Looper;  
6. import android.os.RemoteException;  
7. import android.util.Log;  
8. import android.widget.Toast;  
9. public class mAIDLService extends Service{  
10. private static final String TAG = "AIDLService";  
11.       
12. private void Log(String str){  
13. "----------" + str + "----------");  
14.     }  
15.       
16. public void onCreate(){  
17. "service created");  
18.     }  
19.       
20. public void onStart(Intent intent, int startId){  
21. "service started id = " + startId);  
22.     }  
23.       
24. public IBinder onBind(Intent t){  
25. "service on bind");  
26. return mBinder;  
27.     }  
28.       
29. public void onDestroy(){  
30. "service on destroy");  
31.         super.onDestroy();  
32.     }  
33.       
34. public boolean onUnbind(Intent intent){  
35. "service on unbind");  
36. return super.onUnbind(intent);  
37.     }  
38.       
39. public void onRebind(Intent intent){  
40. "service on rebind");  
41.         super.onRebind(intent);  
42.     }  
43.       
44.       
45. private final mInterface.Stub mBinder = new mInterface.Stub() {       
46. public void invokTest() throws RemoteException {  
47. // TODO Auto-generated method stub  
48. "remote call from client! current thread id = " + Thread.currentThread().getId());  
49.         }  
50.     };  
51. }


注意onBind()函数,返回了mBinder,而mBinder实现了mInterface.Stub,实现了mInterface接口,执行了打印log的操作。

 

整个交互流程如下:

1.客户端通过绑定服务,获取了服务的句柄(本地代理对象);

2.客户端执行onClick(),调用本地代理对象的invokTest()函数,本地代理对象调用mRemote.transact()发出远程调用请求(见   mInterface.java);

3.服务端响应onTransact()执行this.invokTest(),并将执行结果返回;

 

由于客户端只和本地代理对象即服务句柄通信,由代理对象进行真正的IPC操作,所以对客户端来说,IPC过程是透明的,调用远程操作如同调用本地操作一样。在客户端调用transact()时,会将服务描述DSCRIPTION写入到data里,在客户端onTransact时会验证,如果两个不一样,则不能通信。而DSCRIPTION是根据mInterface包名和接口名自动生成的,这就是为什么两个工程里的mInterface.aidl要在同一个包的原因。

 

在这个过程中,mInterface.aidl起到了桥梁的作用,规定统一了客户端和服务端的通信接口,使得客户端和服务端得以成功的通信。

具体的通信transact和onTransact的过程也就是利用Binder驱动通信的过程,在这里就不多叙述。

最后补上两个工程的AndroidManifest.xml


[xhtml]  view plain copy


1. <?xml version="1.0" encoding="utf-8"?>  
2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
3. package="com.styleflying"  
4. android:versionCode="1"  
5. android:versionName="1.0">  
6. <application android:icon="@drawable/icon" android:label="@string/app_name">  
7. <activity android:name=".AIDL.mAIDLActivity"  
8. android:label="@string/app_name">  
9. <intent-filter>  
10. <action android:name="android.intent.action.MAIN" />  
11. <category android:name="android.intent.category.LAUNCHER" />  
12. </intent-filter>  
13. </activity>  
14. </application>  
15. <uses-sdk android:minSdkVersion="8" />  
16. </manifest>


[xhtml]  view plain copy


1. <?xml version="1.0" encoding="utf-8"?>  
2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
3. package="com.styleflying.AIDL"  
4. android:versionCode="1"  
5. android:versionName="1.0">  
6. <application android:icon="@drawable/icon" android:label="@string/app_name">  
7. <service android:name=".mAIDLService">  
8. <intent-filter>  
9. <action android:name="com.styleflying.AIDL.service" />  
10. <category android:name="android.intent.category.DEFAULT" />  
11. </intent-filter>  
12. </service>  
13. </application>  
14. <uses-sdk android:minSdkVersion="8" />  
15. </manifest>