Binder
创建接口和Binder
创建一个继承自IInterface的接口,表示服务端提供了哪些方法(所有在Binder中传输的接口都需要继承IInterface接口)
创建抽象类Stub继承自Binder并实现该接口
Stub类下有asInterface()
,客户端调用此方法可以拿到Stub/Stub.Proxy对象
服务端
创建Stub类对象mBinder并实现接口方法,在onBind()
中将mBinder暴露给外界
客户端
只讨论客户端与服务端不在同一进程的情况,所以客户端拿到的是Stub.Proxy对象
(因为Stub.Proxy实现了IMyAidlInterface,所以mBookManager可以声明为IMyAidlInterface类型)
调用过程
Stub.Proxy对象内部持有着Stub对象(位于服务端)的引用
当客户端发起方法调用请求时,在这里组装好参数后发起transact过程,该过程最终会调用到Stub对象的onTransact()
在Stub对象(位于服务端)的onTransact()
中,去执行具体的目标方法,最后将返回值写入reply参数中
意外情况
Binder运行在服务端进程,如果服务端进程异常终止导致Binder连接断裂,而客户端却不知道,那会有大问题
有两种方式可以重连Binder,两者区别主要是运行的线程不同
-
在客户端
onServiceDisconnected()
中重连Binder
-
在客户端创建DeathRecipient监听器,并在连接到Binder的时候将该监听器注册到Binder上
AIDL
AIDL文件的本质是快速实现Binder的工具,作用是编译后自动生成接口和Binder的实现类Stub...
适用于跨进程方法调用,服务端支持处理并发请求
创建AIDL文件
-
客户端和服务端的所有与aidl相关的类路径需要保持一致
否则运行会出错
-
如果使用自定义类Book 需要创建Book.java并实现Parcelable
然后创建Book.aidl
并且在使用了Book的aidl文件中import
如果单独建了一个aidl文件夹的话,需要在main/build.gradle中添加import路径
-
AIDL接口中除了基本数据类型,其他参数必须标上方向(in传入该方法、out、inout)
使用时的一些Tips
-
AIDL接口中所定义方法都是在实现方的Binder线程池中执行
所以如果方法执行耗时过长,可能会导致另一方ANR
-
使用观察者模式时,注册监听器时服务端反序列化mListener之后得到mListener的Proxy代理对象,随后放入集合;但是在解注册时,客户端传同样的mListener,服务端反序列化之后又会生成一个新的Proxy代理对象,此时去集合中删除是找不到对象的
使用RemoteCallbackList解决
引入权限验证
在服务端定义并声明权限
在服务端的
onBind()
中进行权限验证
如果你没有使用AIDL而是手动实现的Binder,也可以在
Stub:onTransact()
中进行权限校验
\