什么是Binder
Binder是一个类,它实现了IBinder接口,而IBinder接口定义了与远程对象的交互协议。通常在进行跨进程通信时,不需要实现IBinder接口,直接从Binder派生即可。
除了实现IBinder接口外,Binder中还提供了两个重要的接口。
(1)Transact(),客户端调用,用于发送调用请求
(2)onTransact(),服务端响应,用于接收调用请求
因为以上的原因,Binder成为了客户端与服务端的通信媒介,其主要用在Service组件应用中。
Service与客户端通信,有两种方式,AIDL和Messenger。AIDL基于Binder,而Messenger基于AIDL。
AIDL与Binder
如果我们定义一个AIDL文件IMyService.aidl,并在其中定义两个接口,分别为
add(int a, int b)
sub(int a, int b)
编译后,系统将自动生成一个文件IMyService.java,位于gen文件夹下。
打开IMyService,我们可以发现
(1)该文件为接口文件,继承了android.os.IInterface接口
(2)该接口中,定义了AIDL中声明接口的JAVA形式。
(3)该接口中,定义了自身的一个静态抽象子类Stub。
我们先来看IInterface接口,该接口仅有一个需要实现的方法asBinder,用于返回一个Binder对象。
第二点,无需太多说明,毕竟是一个接口,肯定要给出需要实现的接口。
接着来看静态抽象子类Stub
(1)该类实现了IMyService继承自IInterface的方法asBinder。可将将接口转化为Binder。
(2)该类同时提供了一个可以将Binder转化为IMyService实现类的方法,asInterface。
(3)该类继承了android.os.Binder类,重写了Binder类的onTransact方法。该方法的作用是,接收客户端发来的请求,并将请求分发至各个接口。
(4)该类中又自定义了一个静态类Proxy,实现了IMyService。该类在asInterface中被调用。
(5)该类为每个接口方法定义了一个整型的唯一标识。
再来看Proxy类,该类的作用是,作为一个代理,将接收到的请求,转发给服务端。
(1)该类实现了IMyService继承自IInterface的方法asBinder
(2)该类的构造函数,以Binder作为传参,保存为成员变量。
(3)该类实现了IMyService中定义的两个接口。
既然Proxy实现了IMyService中定义的两个接口,那么我们为什么还要对IMyService进行实现呢?
我们继续细看一下两个方法。
(1)add(int a, int b)
(2)sub(int a, int b)
对比一下,可以发现两个方法实现的差不多。都是在接口中调用了Binder的onTransact方法,同时将数据封装为Pacel数据,发送至服务端,起到了代理的作用。
那么什么时候Proxy被调用呢?查找引用发现,Proxy在Stub的asInterface方法中被引用。
Service接口方法调用流程小结
(1)客户端调用bindService绑定服务时,将触发Service的onBind监听方法。该方法将调用asBinder方法,返回一个Binder对象。
(2)客户端将通过onServiceConnected回调函数,获取到该Binder对象(以传参的形式传入)。
(3)客户端获取到Binder对象后,可调用stub.asInterface方法,将其转换为service实现类的对象。
(4)在asInterface方法中,将判断service与当前进程,是否在同一进程中。若是,则返回stub本身,否则返回stub.proxy。返回结果将作为Service实现类的实例。
(5)在通过Service实现类的实例调用接口方法时,若为同一进程,则直接调用方法本身。若为跨进程,则调用stub.proxy的对应接口方法,通过Transact方法将信息传送到服务端。此时,客户端将挂起,等待结果返回。
(6)服务端接收到信息,通过onTransact()方法,根据方法的唯一标识,将信息转发至各对应方法。
(7)信息处理完成后,再由服务端onTransact返回结果。