AIDL使用 进阶2

使用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");


版权声明:本文为u013179982原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。