在Android开发中,使用Service,就不得不提到AIDL,AIDL(AndroidInterface Definition Language)是一种接口定义语言,用于生成可以在Android设备上两个进程之间进行进程间通信(IPC)的代码。使用AIDL语言,可以自动生成服务接口、服务代理、服务Stub代码。
使用AIDL实现IPC服务的步骤如下:
1、 使用AIDL语法,创建.aidl文件,定义服务接口的方法和属性;
2、 在makefile文件中加入.aidl文件,AIDL编译器将自动生成服务接口、服务Stub以及服务代理,即在Android.mk文件的LOCAL_SRC_FILES中加入.aidl文件,如果在Eclipse中开发,刷新下工程就可以在gen目录下看到.aidl文件生成的java文件;
3、 创建一个继承Stub的类并且实现.aidl文件中声明的方法;
4、 向客户端公开接口。
下面我们还是通过之前的RemoteServiceDemo来详细分析AIDL的创建过程及用法。
一、 在aidl文件中定义服务接口
先看示例代码
1. packagecom.example.remoteservicedemo;
2.
3. interface IRemoteService
4. {
5. void count();
6. }
我们可以看到aidl文件的定义和Java类似,第一句是包声明语句,而后是导入声明语句(本例中没有使用,与Java导包类似)。在AIDL中,对于非内建的数据类型,即使在同一文件夹中,也必须显示的进行导入。接下来是名称为IRemoteService的接口声明语句,与Java规则相同,接口名称需与aidl文件名保持一致。示例中声明了count()方法。
在AIDL的语法中,有两个Java接口不具备的特征:
1、接口名称可以使用interface或onewayinterface进行声明,关键字oneway表示当前服务用户请求响应功能时不需要等待应答可以直接调用返回,可用于接口声明或方法声明语句,若接口声明语句使用了oneway关键字,则该接口中声明的所有方法都采用了oneway方式。
2、传递方向指示符,in、out、inout,表示相关参数传递的方向,in表示参数要传递到服务方法内部,out表示将值返回到服务方法的调用端,inout表示传送相应值并接受返回值。
根据以上分析,总结编写AIDL文件时的几个注意点:
1.接口名和aidl文件名相同;
2.接口和方法前不用加访问权限修饰符public,private,protected等,也不能用final,static;
3. AIDL默认支持的类型包括Java基本类型(int、long、boolean等)和(String、List、Map、CharSequence),使用这些类型时不需要import声明。对于List和Map中的元素类型必须是AIDL支持的类型。如果使用自定义类型作为参数或返回值,自定义类型必须实现Parcelable接口。
4.自定义类型和AIDL生成的其它接口类型在aidl描述文件中,应该显式import,即便在该类和定义的包在同一个包中。
5.在aidl文件中所有非Java基本类型参数必须加上in、out、inout标记,以指明参数是输入参数、输出参数还是输入输出参数。
6.Java原始类型默认的标记为in,不能为其它标记。
二、使用AIDL编译器,生成服务接口、服务Stub以及服务代理
如前所述,在Eclipse中创建IRemoteService.aidl文件,自动生成IRemoteService.java文件,其代码内容如下。
1. /*
2. * This file is auto-generated. DO NOT MODIFY. ①
3. * Original file:/home/qinzhonghua/workspace/demo/RemoteServiceDemo/src/com/example/remoteservicedemo/IRemoteService.aidl
4. */
5. packagecom.example.remoteservicedemo;
6. public interfaceIRemoteService extends android.os.IInterface ②
7. {
8. /** Local-side IPCimplementation stub class. */
9. public static abstractclass Stub extends android.os.Binder implements com.example.remoteservicedemo.IRemoteService ③
10. {
11. private static finaljava.lang.String DESCRIPTOR ="com.example.remoteservicedemo.IRemoteService";
12. /** Construct the stubat attach it to the interface. */
13. public Stub()
14. {
15. this.attachInterface(this,DESCRIPTOR);
16. }
17. /**
18. * Cast an IBinder object into ancom.example.remoteservicedemo.IRemoteService interface,
19. * generating a proxy if needed.
20. */
21. public staticcom.example.remoteservicedemo.IRemoteService asInterface(android.os.IBinderobj)
22. {
23. if ((obj==null)) {
24. return null;
25. }
26. android.os.IInterfaceiin = obj.queryLocalInterface(DESCRIPTOR);
27. if (((iin!=null)&&(iininstanceof com.example.remoteservicedemo.IRemoteService))) {
28. return((com.example.remoteservicedemo.IRemoteService)iin);
29. }
30. return newcom.example.remoteservicedemo.IRemoteService.Stub.Proxy(obj);
31. }
32. @Override publicandroid.os.IBinder asBinder()
33. {
34. return this;
35. }
36. @Override public booleanonTransact(int code, android.os.Parcel data, android.os.Parcel reply, intflags) throws android.os.RemoteException ④
37. {
38. switch (code)
39. {
40. caseINTERFACE_TRANSACTION:
41. {
42. reply.writeString(DESCRIPTOR);
43. return true;
44. }
45. case TRANSACTION_count:
46. {
47. data.enforceInterface(DESCRIPTOR);
48. this.count();
49. reply.writeNoException();
50. return true;
51. }
52. }
53. returnsuper.onTransact(code, data, reply, flags);
54. }
55. static final intTRANSACTION_count = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
56. }
57. public void count()throws android.os.RemoteException;
58. }
其中①注释表示该文件自动生成,不可更改,②有AIDL编译器生成的服务接口,继承于IInterface接口,③Stub类继承了Binder类并实现了自动生成的IRemoteService接口,它是具体的服务,④Stub类的onTransact方法从服务用户端接收RPC数据,并调用相应的方法。TRANSACTION_count是count()的RPC代码,RPC代码的生成规则以“TRANSACTION_方法名”形式出现。
三、继承Stub类创建服务
下面要创建一个继承Stub的类,并实现aidl文件中声明的方法,示例代码如下
59. public class ServiceStub extendsIRemoteService.Stub{
60. @Override
61. public void count() throws RemoteException {
62. // TODO Auto-generated method stub
63. mHandler.sendMessage(mHandler.obtainMessage(PRINT_LOG));
64. }
65. }
在onBind方法中返回ServiceStub实例
66. @Override
67. public IBinder onBind(Intent arg0) {
68. // TODO Auto-generated method stub
69. return mBinder;
70. }
71. private final IBinder mBinder = new ServiceStub();
四、服务接口的调用
以上几步的执行已经生成了所需要的服务,那么服务用户是如何使用这些服务的呢?为实现此目的,必须创建一个实现IRemoteService接口的类,使得服务用户可以调用相应的服务。AIDL编译器会自动生成Proxy类,代码如下
72. private static classProxy implements com.example.remoteservicedemo.IRemoteService
73. {
74. privateandroid.os.IBinder mRemote;
75. Proxy(android.os.IBinderremote)
76. {
77. mRemote = remote;
78. }
79. @Override publicandroid.os.IBinder asBinder()
80. {
81. return mRemote;
82. }
83. public java.lang.StringgetInterfaceDescriptor()
84. {
85. return DESCRIPTOR;
86. }
87. @Override public voidcount() throws android.os.RemoteException
88. {
89. android.os.Parcel _data= android.os.Parcel.obtain();
90. android.os.Parcel _reply= android.os.Parcel.obtain();
91. try {
92. _data.writeInterfaceToken(DESCRIPTOR);
93. mRemote.transact(Stub.TRANSACTION_count,_data, _reply, 0);
94. _reply.readException();
95. }
96. finally {
97. _reply.recycle();
98. _data.recycle();
99. }
100. }
101. }
与服务一样,实现IRemoteService接口,生成调用服务count()方法的RPC数据,RPC数据中表示调用count()方法的RPC代码(TRANSACTION_count)以及IRemoteService接口信息作为参数传递给BinderProxy的transact()方法,而后通过Binder IPC将RPC数据传递给RemoteService服务,调用服务的count()方法。