Android基础——初学者必知的AIDL在应用层上的Binder机制

初学者必知的AIDL在应用层上的Binder机制

首先得理解几个概念:

IPC:Inter-Process Communication,进程间的通信或跨进程通信。简单点理解,一个应用可以存在多个进程,但需要数据交换就必须用IPC;或者是二个应用之间的数据交换。

Binder:Binder是Android的一个类,它实现了IBinder接口。从IPC角度来说,Binder是Android中的一种跨进程通信方式。通过这个Binder对象,客户端就可以获取服务端提供的服务或数据,这里的服务包括普通服务和基于AIDL的服务。

AIDL:Android Interface Definition language,它是一种Android内部进程通信接口的描述语言。

一、AIDL的使用

服务端:

创建一个服务端工程,在工程中点击右键New->AIDL->AIDL File,默认直接点确定,这时会在工程中出现一个aidl文件:

我们打开这个aidl文件,我们创建一个我们需要测试的方法:

由于Android Studio是要手动编译才能生成对应AIDL的java文件,既然aidl文件是个接口,那就必须存在着实现这个接口的类,点击编译,系统自动生成一个java类,该java类的代码就是整个Binder机制的原理所在(会在下面第二步骤介绍原理):

既然是个服务端,那么我们就要开始写服务了,创建一个类,继承Service:



既然是个服务,就必须在manifests文件中配置:


到现在服务端写好了,开启模拟器启动这个程序,记得在代码中开启服务:



 

客户端:

 

在工程中点击右键New->Module,按默认确定,finish:


关键的一步来了,复制服务端的aidl整个文件夹(包括里面的包、aidl文件、完整无缺)粘贴到客户端对应放aidl的地方


不要忘了,客户端还要手动编译

好了我们来写客户端的代码(我们在MainActivity中放一个”AIDL“的按钮,先绑定服务,然后点击按钮调用):



测试结果(先开启服务端,开启服务后,接着开启客户端,绑定远程服务):




 

二、AIDL的Binder机制原理分析

 

分析原理:



我们来分析一下这个类

首先本身继承Iinterface,所以他也是个接口,接口中必须有方法,代码定位到结尾有2个方法。


这两个方法就是basicTypes和add,就是我们服务端的2个方法。

接着发现该接口中有1个内部类Stub,继承自本身(IMyAidlInterface)接口,代码定位到Stub类。

这个Stub有个构造方法、asInterface、asBinder、onTransact(先不介绍)。

接着发现该内部类Stub还有一个内部类,代码定位到Proxy(我们把它称为代理)类,也是继承自本身(IMyAidlInterface)接口,所以实现该接口的两个方法。


在这个类里面我们会发现有2个标识:用来区分两个方法,到底你远程请求哪个方法的唯一标识,代码定位到代理类的结尾


回过头来,还记得我们客户端做了什么吗?答案:绑定一个服务,在回调方法获取一个接口(iMyAidlInterface),它是直接静态使用IMyAidlInterface里面的静态类Stub的asInterface的方法:(雅思高分作文好了我们去跟踪到Stub类asInterface这个方法)


代码定位到Stub类asInterface方法


前面只是做一些判断、看一下最后一句话:我们将传过来的obj还是传给了它的代理类来处理,返回的是代理类的对象


所以在客户端的iMyAidlInterface=……,则是拿到它的代理类,好了,这个时候就看客户端调用代理类干嘛了


他调用了代理类的add方法,代码定位到代理类的add方法


你会发现,它把数据写进了_data里面,最后调用transact方法,传入_data数据,唯一标识Stub.TRANSACTION_add。


然后这个transact方法就是通过底层了,通过底层结束后,这些参数送到哪了?答案:底层会走到stub类中的onTransact方法,通过判断唯一标识,确定方法:


在这个地方将传过来的参数解包,readInt方法。然后调用this.add方法,this指的就是服务端,调用服务端的add的方法:


将得到的结果,写入reply


最后一句话,最后返回系统的ontransact方法,传入结果reply:


所以我们在上面获得的结果就是reply(答案:3):


最后总结下整个过程



三、AIDL编写时候的一些错误

错误一:


这个错误很有可能是你写的服务端,忘记返回myS了,返回的是个null


错误二:

 


这个错误很有可能是的服务端在manifests文件中少了exported="true"的属性 

原文地址:https://www.cnblogs.com/zhanglixina/p/9597625.html