在Android中,如果我们需要在不同进程间实现通信,就需要用到AIDL技术去完成。

AIDL(Android Interface Definition Language)是一种接口定义语言,编译器通过*.aidl文件的描述信息生成符合通信协议的Java代码,我们无需自己去写这段繁杂的代码,只需要在需要的时候调用即可,通过这种方式我们就可以完成进程间的通信工作。关于AIDL的编写规则我在这里就不多介绍了,读者可以到网上查找一下相关资料。

接下来,我就演示一个操作AIDL的最基本的流程。

首先,我们需要建立一个服务端的工程,如图所以:

 

在IPerson.aidl中我们定义了一个“问候”的方法,代码如下:



[java] 
    view plain
     copy 
    

      
    
 
  
1. package com.scott.aidl;  
2. interface IPerson {  
3.     String greet(String someone);  
4. }


 

在Eclipse插件的帮助下,编译器会自动在gen目录中生成对应的IPerson.java文件,格式化后的代码如下:

 


[java] 
    view plain
     copy 
    

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


 

该文件的大纲视图如下:

IPerson接口中的抽象内部类Stub继承android.os.Binder类并实现IPerson接口,比较重要的方法是asInterface(IBinder)方法,该方法会将IBinder类型的对象转换成IPerson类型,必要的时候生成一个代理对象返回结果。

接下来就是我们的Service了:

 



[java] 
    view plain
     copy 
    

      
    
 
  
1. package com.scott.server;  
2.   
3. import android.app.Service;  
4. import android.content.Intent;  
5. import android.os.IBinder;  
6. import android.os.RemoteException;  
7. import android.util.Log;  
8.   
9. import com.scott.aidl.IPerson;  
10.   
11. public class AIDLService extends Service {  
12.   
13. private static final String TAG = "AIDLService";  
14.       
15. new IPerson.Stub() {  
16. @Override  
17. public String greet(String someone) throws RemoteException {  
18. "greet() called");  
19. return "hello, " + someone;  
20.         }  
21.     };  
22.       
23. @Override  
24. public IBinder onBind(Intent intent) {  
25. "onBind() called");  
26. return stub;  
27.     }  
28.       
29. @Override  
30. public boolean onUnbind(Intent intent) {  
31. "onUnbind() called");  
32. return true;  
33.     }  
34.       
35. @Override  
36. public void onDestroy() {  
37. super.onDestroy();  
38. "onDestroy() called");  
39.     }  
40. }

 

我们实现了IPerson.Stub这个抽象类的greet方法,然后再onBind(Intent)方法中返回我们的stub实例,这样一来调用方获取的IPerson.Stub就是我们的这个实例,greet方法也会按照我们的期望那样执行。

当然,要想让Service生效,我们还需要在AndroidManifest.xml中做一些配置工作:

 



[java] 
    view plain
     copy 
    

      
    
 
  
1. <service android:name=".AIDLService">  
2.     <intent-filter>  
3. "android.intent.action.AIDLService" />  
4. "android.intent.category.DEFAULT" />  
5.     </intent-filter>  
6. </service>

 

服务端已经完成了,接下来我们就该完成客户端的工作了。我已经建好了一个客户端工程,如图:

我们只需要把IPerson.aidl文件拷到相应的目录中即可,编译器同样会生成相对应的IPerson.java文件,这一部分和服务端没什么区别。这样一来,服务端和客户端就在通信协议上达到了统一。我们主要工作在MainActivity中完成。

MainActivity代码如下:

 

[java] 
    view plain
     copy 
    

      
    
 
  
1. package com.scott.client;  
2.   
3. import android.app.Activity;  
4. import android.content.ComponentName;  
5. import android.content.Context;  
6. import android.content.Intent;  
7. import android.content.ServiceConnection;  
8. import android.os.Bundle;  
9. import android.os.IBinder;  
10. import android.os.RemoteException;  
11. import android.util.Log;  
12. import android.view.View;  
13. import android.widget.Button;  
14. import android.widget.Toast;  
15.   
16. import com.scott.aidl.IPerson;  
17.   
18. public class MainActivity extends Activity {  
19.   
20. private Button bindBtn;  
21. private Button greetBtn;  
22. private Button unbindBtn;  
23.   
24. private IPerson person;  
25. private ServiceConnection conn = new ServiceConnection() {  
26.   
27. @Override  
28. public void onServiceConnected(ComponentName name, IBinder service) {  
29. "ServiceConnection", "onServiceConnected() called");  
30.             person = IPerson.Stub.asInterface(service);  
31.         }  
32.   
33. @Override  
34. public void onServiceDisconnected(ComponentName name) {  
35. //This is called when the connection with the service has been unexpectedly disconnected,  
36. //that is, its process crashed. Because it is running in our same process, we should never see this happen.  
37. "ServiceConnection", "onServiceDisconnected() called");  
38.         }  
39.     };  
40.   
41. @Override  
42. public void onCreate(Bundle savedInstanceState) {  
43. super.onCreate(savedInstanceState);  
44.         setContentView(R.layout.main);  
45.   
46.         bindBtn = (Button) findViewById(R.id.bindBtn);  
47. new View.OnClickListener() {  
48. @Override  
49. public void onClick(View v) {  
50. new Intent("android.intent.action.AIDLService");  
51.                 bindService(intent, conn, Context.BIND_AUTO_CREATE);  
52.                   
53. false);  
54. true);  
55. true);  
56.             }  
57.         });  
58.   
59.         greetBtn = (Button) findViewById(R.id.greetBtn);  
60. new View.OnClickListener() {  
61. @Override  
62. public void onClick(View v) {  
63. try {  
64. "scott");  
65. this, retVal, Toast.LENGTH_SHORT).show();  
66. catch (RemoteException e) {  
67. this, "error", Toast.LENGTH_SHORT).show();  
68.                 }  
69.             }  
70.         });  
71.   
72.         unbindBtn = (Button) findViewById(R.id.unbindBtn);  
73. new View.OnClickListener() {  
74. @Override  
75. public void onClick(View v) {  
76.                 unbindService(conn);  
77.                   
78. true);  
79. false);  
80. false);  
81.             }  
82.         });  
83.     }  
84. }

 

从代码中可以看到,我们要重写ServiceConnection中的onServiceConnected方法将IBinder类型的对像转换成我们的IPerson类型。到现在我们就剩下最后一个步骤了,这个环节也是最为关键的,就是绑定我们需要的服务。我们通过服务端Service定义的“android.intent.action.AIDLService”这个标识符来绑定其服务,这样客户端和服务端就实现了通信的连接,我们就可以调用IPerson中的“问候”方法了。

最后,贴几张客户端演示过程图。

 

 

 

 按照顺序分别是:初始界面;点击bindService后界面;点击greet后界面;点击unbindService后界面。

操作过程中的日志如下: