AIDL进程间通信详解
2016-05-12 11:09
477 查看
什么是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中序需手动编译)
创建这个AIDL文件后,如果没有错误,eclipse会在工程的gen目录下面生成对应名字的 java文件,这个文件则会生成 IRemoteService.java文件,后面我们会详细解析一下这个文件。
2.服务端实现这个接口,也就是实现 add(int numA, int numB) 这个方法
3.共享这个接口给客户端
在客户端的这个程序中,加入同样的 .aidl 文件
首先客户端显示绑定Intent
AIDl 默认支持的数据类型:
1.基本数据类型(short类型不支持,在 writeToParcel 序列化时中没有 writeShort 方法)
2.String 、 CharSequence
3. List 、 Map
4.序列化后的对象
分析 ,aidl 文件编译器生成同名的 .java 文件,我们需要明白其内部机制,它是如何进行进程间通信的?
这个是生成 java文件的大致结构,下面我们会依次解释里面的方法。
生成与 .aidl 文件同名的接口,其中包括(Stub类,add方法)
在Stub类中有几个很重要的方法或类:asInterface ; onTransact ; Proxy(代理类)
我们先来看看 asInterface 方法:
再来看看代理类里面发生了什么事?
Ok,Ok,在 transact 中,我们调用了 onTransact 方法,我们再来一步一步看看onTransact 方法吧。
这是整个过程的结构图:
如果有什么错误,请大家多多提出,谢谢。
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; //AIDL语言类似于java接口写法 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启动,绑定服务 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) { //拿到远程服务,是一个Proxy代理类 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; //AIDL语言类似于java接口写法 //自动生成文件,不能修改 public interface IRemoteService extends android.os.IInterface { //本地端生成一个抽象存根类 public static abstract class Stub extends android.os.Binder implements com.test.aidl.IRemoteService { //静态描述符,用于标识整个 .aidl 文件 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() //在代理类Proxy调用Transact方法只会调用 onTransact方法 @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException //代理类,运用代理模式。调用transact方法,将序列化数据通过系统底层传输到Stub类,调用onTransact方法 private static class Proxy implements com.test.aidl.IRemoteService // 给 .aidl 文件中的远程调用方法,指定一个code,用于标识,在onTransact方法中去判断 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是一个代理类
//拿到远程服务,是一个Proxy代理类 iRemoteService = IRemoteService.Stub.asInterface(service);
再来看看代理类里面发生了什么事?
//代理类,运用代理模式。调用transact方法,将序列化数据通过系统底层传输到Stub类,调用onTransact方法 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); //通过transact方法将数据通过系统底层发送出去 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); }
//调用onTransact方法,将数据传入 boolean r = onTransact(code, data, reply, flags); if (reply != null) { reply.setDataPosition(0); } return r; }
Ok,Ok,在 transact 中,我们调用了 onTransact 方法,我们再来一步一步看看onTransact 方法吧。
//在代理类Proxy调用Transact方法只会调用 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 表示客户端请求会失败。
这是整个过程的结构图:
如果有什么错误,请大家多多提出,谢谢。
相关文章推荐
- Failed to create the part's controls解决方法
- 郭霖的反编译http://blog.csdn.net/guolin_blog/article/details/49738023
- std::pair<MAP::iterator,bool>用法,可用来判断插入式否成功
- impdp failed with ORA-39002, ORA-31694 and ORA-31644
- Undefined symbols for architecture x86_64: ( linker command failed with exit code 1)
- ARPG游戏中怪物AI实现
- SVN中 “containing working copy admin area is missing” 问题
- Determining IP information for eth0... failed
- 线程控制-sigwait函数和相关函数解释
- loadrunner:Action.c(4): Error -27796: Failed to connect to server "192.168.66.3:8080": [10060] Connection timed out
- eerTyraniBafonoitazilaireSredroerPyfireV.331
- public static void main(String[] args)
- Failed to start LSB:Bring up/down networking(已解决)
- RAID详细介绍
- RAID详细介绍
- leetcode 196. Delete Duplicate Emails delete
- HDU 4391 Paint The Wall
- ARPG游戏中怪物AI实现
- 第五届山东省ACM angry_birds_again_and_again(积分)
- 172. Factorial Trailing Zeroes