转载出处:http://blog.csdn.net/u012883858/article/details/51374525
什么是AIDL?
IDL是一种内部进程间通信的描述语言,而AIDL,则是Android中内部进程间通信的描述语言,Android接口定义语言。(Android Interface Definition Language)
AIDL有什么作用呢?
进程间通信,也就是说在Android手机中,每一个应用程序都拥有自己的虚拟机,他们是没有办法直接进行数据之间的交换的,我们需要通过某种方式才能实现进程间的通信,那么,Android中我们就可以通过AIDL来实现进程间通信,AIDL通过系统底层来实现进程间通信,且基于Service 。
AIDL的特点是什么?
谷歌官方文档中说:
使用Binder的情况是:有IPC(进程间通信),没有多线程,多个应用程序;
使用Messenger情况是:只有IPC,没有多线程;
使用AIDL情况是:有IPC,多线程,且多个应用程序;只有你允许客户端从不同的应用程序,为了进程间的通信而去访问你的Service,以及想在你的Service处理多线程才会使用。
AIDL基本语法:
1.语法和Java的接口类似
2.AIDL只支持方法,不能定义静态成员
3.AIDL运行方法有任何类型的参数和返回值
4.除默认类型外,均需要导包
AIDL如何使用?
1.创建你的 .aidl 文件(eclipse中自动编译,Android Studio中序需手动编译)
-
- package com.test.aidl;
-
- interface IRemoteService{
- int add(int numA,int numB);
- }
创建这个AIDL文件后,如果没有错误,eclipse会在工程的gen目录下面生成对应名字的 java文件,这个文件则会生成 IRemoteService.java文件,后面我们会详细解析一下这个文件。
2.服务端实现这个接口,也就是实现 add(int numA, int numB) 这个方法
-
- public class RemoteService extends Service{
-
-
-
-
- @Override
- public IBinder onBind(Intent intent) {
-
- return iBinder;
- }
-
- private IBinder iBinder = new IRemoteService.Stub() {
-
- @Override
- public int add(int numA, int numB) throws RemoteException {
-
- return numA + numB;
- }
- };
- }
3.共享这个接口给客户端
在客户端的这个程序中,加入同样的 .aidl 文件
首先客户端显示绑定Intent
-
- Intent intent = new Intent();
-
- intent.setComponent(new ComponentName
- ("package com.test.aidl","package com.test.aidl.IRemoteService"));
- bindService(intent , conn , Context.BIND_AUTO_CREATE);
在ServiceConnection中,获取远程服务
- IRemoteService iRemoteService;
- private ServiceConnection conn=new ServiceConnection() {
-
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- iRemoteService = null;
- }
-
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
-
-
- iRemoteService = IRemoteService.Stub.asInterface(service);
-
- }
- };
通过 iRemoteService 就可以调用方法了
- try{
-
- int res = iRemoteService.add(num1,num2);
- }catch (RemoteException e){
- e.printStackTrace();
- }
整个过程就是AIDL的进程间通信了,记住,在两个进程(程序)中都要放入相同的 .aidl 文件。
AIDl 默认支持的数据类型:
1.基本数据类型(short类型不支持,在 writeToParcel 序列化时中没有 writeShort 方法)
2.String 、 CharSequence
3. List 、 Map
4.序列化后的对象
分析 ,aidl 文件编译器生成同名的 .java 文件,我们需要明白其内部机制,它是如何进行进程间通信的?
这个是生成 java文件的大致结构,下面我们会依次解释里面的方法。
- package com.test.aidl;
-
-
- public interface IRemoteService extends android.os.IInterface
- {
-
-
- public static abstract class Stub extends android.os.Binder implements com.test.aidl.IRemoteService
- {
-
-
- private static final java.lang.String DESCRIPTOR = "com.test.aidl.IRemoteService";
-
-
- public Stub()
-
-
- public static com.test.aidl.IRemoteService asInterface(android.os.IBinder obj)
-
- @Override
- public android.os.IBinder asBinder()
-
-
- @Override
- public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
-
-
-
- private static class Proxy implements com.test.aidl.IRemoteService
-
-
-
- static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
- }
-
-
- public int add(int numA, int numB) throws android.os.RemoteException;
- }
相信很清楚了吧。
生成与 .aidl 文件同名的接口,其中包括(Stub类,add方法)
在Stub类中有几个很重要的方法或类:asInterface ; onTransact ; Proxy(代理类)
我们先来看看 asInterface 方法:
-
- public static com.test.aidl.IRemoteService asInterface(android.os.IBinder obj)
- {
- if ((obj==null)) {
- return null;
- }
- android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
- if (((iin!=null)&&(iin instanceof com.test.aidl.IRemoteService))) {
- return ((com.test.aidl.IRemoteService)iin);
- }
- return new com.test.aidl.IRemoteService.Stub.Proxy(obj);
- }
这个方法是在客户端调用,此时的 iRemoteService是一个代理类
-
- Service = IRemoteService.Stub.asInterface(service);
再来看看代理类里面发生了什么事?
-
- private static class Proxy implements com.test.aidl.IRemoteService
- {
- private android.os.IBinder mRemote;
- Proxy(android.os.IBinder remote)
- {
- mRemote = remote;
- }
- @Override
- public android.os.IBinder asBinder()
- {
- return mRemote;
- }
- public java.lang.String getInterfaceDescriptor()
- {
- return DESCRIPTOR;
- }
- @Override
- public int add(int numA, int numB) 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);
- _data.writeInt(numA);
- _data.writeInt(numB);
-
- mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
- _reply.readException();
- _result = _reply.readInt();
- }
- finally {
- _reply.recycle();
- _data.recycle();
- }
- return _result;
- }
- }
最重要的就是在代理类中,我们调用了 transact 方法,把我们的数据从客户端传输出去。transact 是Binder类的一个方法,我们就去Binder的源码之中看看,transact是怎么实现的吧?
- public final boolean transact(int code, Parcel data, Parcel reply,
- int flags) throws RemoteException {
- if (false) Log.v("Binder", "Transact: " + code + " to " + this);
- if (data != null) {
- data.setDataPosition(0);
- }
-
- boolean r = onTransact(code, data, reply, flags);
- if (reply != null) {
- reply.setDataPosition(0);
- }
- return r;
- }
Ok,Ok,在 transact 中,我们调用了 onTransact 方法,我们再来一步一步看看onTransact 方法吧。
-
- @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_add:
- {
- data.enforceInterface(DESCRIPTOR);
- int _arg0;
- _arg0 = data.readInt();
- int _arg1;
- _arg1 = data.readInt();
- int _result = this.add(_arg0, _arg1);
- reply.writeNoException();
- reply.writeInt(_result);
- return true;
- }
- }
- return super.onTransact(code, data, reply, flags);
- }
我们就在 onTransact 中处理客户端传来的数据,服务端通过 code 来确定客户端所请求的目标方法,从 data中取出目标方法所需参数,执行完目标方法后,向 reply 之中写入返回值,这就是 onTransact 方法执行过程,如果此方法返回 false 表示客户端请求会失败。
这是整个过程的结构图: