AIDL进程间通信详解

转载出处: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中序需手动编译)

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //包名  
  2. package com.test.aidl;  
  3. //AIDL语言类似于java接口写法  
  4. interface IRemoteService{  
  5.         int add(int numA,int numB);  
  6. }  

创建这个AIDL文件后,如果没有错误,eclipse会在工程的gen目录下面生成对应名字的 java文件,这个文件则会生成 IRemoteService.java文件,后面我们会详细解析一下这个文件。

2.服务端实现这个接口,也就是实现 add(int numA, int numB) 这个方法

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //服务端对信息的共享  
  2. public class RemoteService extends Service{  
  3.   
  4.     /** 
  5.      * 当客户端绑定该服务时会执行 
  6.      */  
  7.     @Override  
  8.     public IBinder onBind(Intent intent) {  
  9.           
  10.         return iBinder;  
  11.     }  
  12.       
  13.     private IBinder iBinder = new IRemoteService.Stub() {  
  14.           
  15.         @Override  
  16.         public int add(int numA, int numB) throws RemoteException {  
  17.               
  18.             return numA + numB;  
  19.         }  
  20.     };  
  21. }  

3.共享这个接口给客户端

在客户端的这个程序中,加入同样的 .aidl 文件

首先客户端显示绑定Intent

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //获取到服务端  
  2.         Intent intent = new Intent();  
  3.         //显示Intent启动,绑定服务  
  4.         intent.setComponent(new ComponentName  
  5.                 ("package com.test.aidl","package com.test.aidl.IRemoteService"));  
  6.         bindService(intent , conn , Context.BIND_AUTO_CREATE);  
在ServiceConnection中,获取远程服务

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. IRemoteService iRemoteService;  
  2.     private ServiceConnection conn=new ServiceConnection() {  
  3.           
  4.         //绑定上服务  
  5.         @Override  
  6.         public void onServiceDisconnected(ComponentName name) {  
  7.             iRemoteService = null;  
  8.         }  
  9.         //服务断开的时候  
  10.         @Override  
  11.         public void onServiceConnected(ComponentName name, IBinder service) {  
  12.               
  13.             //拿到远程服务,是一个Proxy代理类  
  14.             iRemoteService = IRemoteService.Stub.asInterface(service);  
  15.               
  16.         }  
  17.     };  
通过 iRemoteService 就可以调用方法了 

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. try{  
  2.             //注意抛出远程异常  
  3.             int res = iRemoteService.add(num1,num2);  
  4.         }catch (RemoteException e){  
  5.             e.printStackTrace();  
  6.         }  
整个过程就是AIDL的进程间通信了,记住,在两个进程(程序)中都要放入相同的  .aidl 文件。


AIDl 默认支持的数据类型:

1.基本数据类型(short类型不支持,在 writeToParcel 序列化时中没有 writeShort 方法)

2.String 、 CharSequence

3. List 、 Map

4.序列化后的对象


分析 ,aidl 文件编译器生成同名的 .java 文件,我们需要明白其内部机制,它是如何进行进程间通信的?

这个是生成 java文件的大致结构,下面我们会依次解释里面的方法。

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package com.test.aidl;  
  2. //AIDL语言类似于java接口写法  
  3. //自动生成文件,不能修改     
  4. public interface IRemoteService extends android.os.IInterface  
  5. {  
  6.   
  7. //本地端生成一个抽象存根类  
  8. public static abstract class Stub extends android.os.Binder implements com.test.aidl.IRemoteService  
  9. {  
  10.       
  11. //静态描述符,用于标识整个 .aidl 文件   
  12. private static final java.lang.String DESCRIPTOR = "com.test.aidl.IRemoteService";  
  13.   
  14. //在构造函数中绑定类名(静态描述符)  
  15. public Stub()  
  16.   
  17. //客户端调用此方法,返回一个远程服务的代理类  
  18. public static com.test.aidl.IRemoteService asInterface(android.os.IBinder obj)  
  19.   
  20. @Override   
  21. public android.os.IBinder asBinder()  
  22.   
  23. //在代理类Proxy调用Transact方法只会调用 onTransact方法  
  24. @Override   
  25. public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException  
  26.   
  27.   
  28. //代理类,运用代理模式。调用transact方法,将序列化数据通过系统底层传输到Stub类,调用onTransact方法  
  29. private static class Proxy implements com.test.aidl.IRemoteService  
  30.   
  31.   
  32. // 给 .aidl 文件中的远程调用方法,指定一个code,用于标识,在onTransact方法中去判断  
  33. static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);  
  34. }  
  35.   
  36. //接口中的方法  
  37. public int add(int numA, int numB) throws android.os.RemoteException;  
  38. }  
相信很清楚了吧。

生成与 .aidl 文件同名的接口,其中包括(Stub类,add方法)

在Stub类中有几个很重要的方法或类:asInterface ;  onTransact ;  Proxy(代理类)


我们先来看看 asInterface 方法:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //客户端调用此方法,返回一个远程服务的代理类  
  2. public static com.test.aidl.IRemoteService asInterface(android.os.IBinder obj)  
  3. {  
  4. if ((obj==null)) {  
  5. return null;  
  6. }  
  7. android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);  
  8. if (((iin!=null)&&(iin instanceof com.test.aidl.IRemoteService))) {  
  9. return ((com.test.aidl.IRemoteService)iin);  
  10. }  
  11. return new com.test.aidl.IRemoteService.Stub.Proxy(obj);  
  12. }  
这个方法是在客户端调用,此时的 iRemoteService是一个代理类
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //拿到远程服务,是一个Proxy代理类  
  2. Service = IRemoteService.Stub.asInterface(service);  


再来看看代理类里面发生了什么事?

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //代理类,运用代理模式。调用transact方法,将序列化数据通过系统底层传输到Stub类,调用onTransact方法  
  2. private static class Proxy implements com.test.aidl.IRemoteService  
  3. {  
  4. private android.os.IBinder mRemote;  
  5. Proxy(android.os.IBinder remote)  
  6. {  
  7. mRemote = remote;  
  8. }  
  9. @Override   
  10. public android.os.IBinder asBinder()  
  11. {  
  12. return mRemote;  
  13. }  
  14. public java.lang.String getInterfaceDescriptor()  
  15. {  
  16. return DESCRIPTOR;  
  17. }  
  18. @Override   
  19. public int add(int numA, int numB) throws android.os.RemoteException  
  20. {  
  21. android.os.Parcel _data = android.os.Parcel.obtain();  
  22. android.os.Parcel _reply = android.os.Parcel.obtain();  
  23. int _result;  
  24. try {  
  25. //代理类中将数据序列化  
  26. _data.writeInterfaceToken(DESCRIPTOR);  
  27. _data.writeInt(numA);  
  28. _data.writeInt(numB);  
  29. //通过transact方法将数据通过系统底层发送出去  
  30. mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);  
  31. _reply.readException();  
  32. _result = _reply.readInt();  
  33. }  
  34. finally {  
  35. _reply.recycle();  
  36. _data.recycle();  
  37. }  
  38. return _result;  
  39. }  
  40. }  
最重要的就是在代理类中,我们调用了 transact 方法,把我们的数据从客户端传输出去。transact 是Binder类的一个方法,我们就去Binder的源码之中看看,transact是怎么实现的吧?

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public final boolean transact(int code, Parcel data, Parcel reply,  
  2.             int flags) throws RemoteException {  
  3.         if (false) Log.v("Binder""Transact: " + code + " to " + this);  
  4.         if (data != null) {  
  5.             data.setDataPosition(0);  
  6.         }  
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1.     //调用onTransact方法,将数据传入  
  2.     boolean r = onTransact(code, data, reply, flags);  
  3.     if (reply != null) {  
  4.         reply.setDataPosition(0);  
  5.     }  
  6.     return r;  
  7. }  

Ok,Ok,在 transact 中,我们调用了 onTransact 方法,我们再来一步一步看看onTransact 方法吧。

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //在代理类Proxy调用Transact方法只会调用 onTransact方法  
  2. @Override   
  3. public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException  
  4. {  
  5. switch (code)  
  6. {  
  7. case INTERFACE_TRANSACTION:  
  8. {  
  9. reply.writeString(DESCRIPTOR);  
  10. return true;  
  11. }  
  12. case TRANSACTION_add:  
  13. {  
  14. data.enforceInterface(DESCRIPTOR);  
  15. int _arg0;  
  16. _arg0 = data.readInt();  
  17. int _arg1;  
  18. _arg1 = data.readInt();  
  19. int _result = this.add(_arg0, _arg1);  
  20. reply.writeNoException();  
  21. reply.writeInt(_result);  
  22. return true;  
  23. }  
  24. }  
  25. return super.onTransact(code, data, reply, flags);  
  26. }  
我们就在 onTransact 中处理客户端传来的数据,服务端通过 code 来确定客户端所请求的目标方法,从 data中取出目标方法所需参数,执行完目标方法后,向 reply 之中写入返回值,这就是 onTransact 方法执行过程,如果此方法返回 false 表示客户端请求会失败。

这是整个过程的结构图:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值