使用aidl 后如何彼此检测远程服务和客户端的生命周期。如果不能监控那将有一个很严重问题,程序可能会出现Crash ,报的基本是一个远程服务已经不存在。
1.客户端如何检测服务端是否连接
基本有三种方式:
- 调用远程方法的时候捕获RemoteException(DeadObjectException);
- 调用IBinder的pingBinder()进行检测;
- 实现IBinder.DeathRecipient接口回调
前两种是比较被动的,一般是你去使用的时候才去调用和验证。
相比第三种比较靠谱些。
基本使用就是将
onServiceConnected 方法的参数IBinder 注册监听器
service.linkToDeath (new IBinder.DeathRecipient () {
@Override
public void binderDied() {
}
},0);
当远程服务端异常终止或者死亡时就会触发binderDied。
2.服务端如何监控客户端注册的接口的生命
方法基本有四种:
- 调用远程方法的时候捕获RemoteException(DeadObjectException);
- 调用IBinder的pingBinder()进行检测;
- 监控客户端的服务的生命周期比如unBind()
- 通过RemoteCallbackList 来监控
前两种方式是比较被动的,通过组合判断的方式,也可以知道当前注册的客户端的接口是否已不在存活。
第三种方式按道理也可以,但是在实践中发现有些特殊场景unBind 是不会执行的,所以这就注定了这种方案行不通。
重点讲RemoteCallbackList
将客户端注册的接口类添加到RemoteCallbackList 集合中
比如
private final static RemoteCallbackList<IDeviceObserver> mEventObservers = new RemoteCallbackList<> ();
protected synchronized static void addObserver(IDeviceObserverobserver) { mEventObservers .register (observer); } protected synchronized static void removeObserver(IDeviceObserverobserver) { mEventObservers .unregister (observer); }
触发回掉函数
int remoteClients = mEventObservers.beginBroadcast ();
try {
for (int i = 0; i < remoteClients; i++) {
mEventObservers.getBroadcastItem (i).onDeviceEvent (parcelProxy);
}
} catch (RemoteException e) {
Log.e (TAG, Log.getStackTraceString (e));
}
mEventObservers.finishBroadcast ();
这里的onDeviceEvent 就是IDeviceObserver 客户端注册接口的方法,执行完上述代码后就触发了客户端的回掉。
但是这里有个坑,这个操作必须保持同步操作,也就是调用beginBroadcast 到调用finishBroadcast,不能中断或者过程中再调用finishBroadcast ,否则会报
throw new IllegalStateException(
"beginBroadcast() called while already in a broadcast");
或者
throw new IllegalStateException(
"finishBroadcast() called outside of a broadcast");
3. AIDL 中 in out inout 使用
IN :代表输入,被in 标识过的对象只能由写入端(简称client)修改,对端(service)收到对象修改后不能改变写入端client 数据(改变后client 不会改变),相当于service 收到了一份克隆后的数据,client 数据改变service 并不能感知,只能被动接受client数据。
OUT: 代表输出,被out 标识过的 client 对象,client 调用接口传递数据到service改数 ,也就是在服务端执行方法的时候,并不会去读取客户端的这个参数,而是自己new一个新对象,用此新对象来作为参数执行方法。但是在方法执行完之后,会把这个参数又传回客户端,更新客户端的对象参数值。也就是service 数据改变client 并不能感知,只能被动接受service 改变后的值。
INOUT: 表示两端都可以修改,并且数据内容会在client 和service 两端同步,相互之间都是可以传递和感知的。