DeadObjectException:
Binder 为CS架构,我们无法确保Client端的生命周期,如被forcestop或被卸载等等。如果server端提供了接口回调的方式,一旦Client被停用,那么就会出现DeadObjectException的异常,原因是在Server进行Callback时,Client端已经死亡。
安卓本身提供了一些检测方法,拿com.android.server.location.RemoteListenerHelper来举例,
GpsStatus在注册时会通过LocationManager-->LocationManagerService-->.........-->最终会注册到com.android.server.location.RemoteListenerHelper
这是一个典型的跨进程服务,由LocationManager对外提供服务,
LocationManager.addGpsStatusListener();这个方法注册到了system_server内,进行卫星的状态变更等。
系统是这样进行处理的:
public boolean addListener(@NonNull TListener listener) {
......
......
LinkedListener deathListener = new LinkedListener(listener);
synchronized (mListenerMap) {
if (mListenerMap.containsKey(binder)) {
// listener already added
return true;
}
try {
binder.linkToDeath(deathListener, 0 /* flags */);
} catch (RemoteException e) {
// if the remote process registering the listener is already death, just swallow the
// exception and continue
Log.e(mTag, "Remote listener already died.", e);
return false;
}
mListenerMap.put(binder, deathListener);
......
......
}
return true;
}
注意加粗部分,lintToDeath,注册了死亡通知,在Client binder死亡后会进行Callback,我们可以在Callback内进行逻辑处理,这里需要一个实现了IBinder.DeathRecipient接口的对象,方法如下:
private class LinkedListener implements IBinder.DeathRecipient {
......
......
@Override
public void binderDied() {
Log.d(mTag, "Remote Listener died: " + mListener);
removeListener(mListener);
}
}
加粗部分,一旦被Client Binder死亡后 就会在这里进行Callback,我们可以在这里进行逻辑处理,如这里的逻辑是,如果Client Binder死亡,那么就反注册掉卫星的Callback。
这种是framework里比较常用的做法。
如果Callback 被Client主动清除,那么需要进行unlinkToDeath的操作,代码如下:
public boolean removeListener(@NonNull TListener listener) {
......
if (linkedListener != null) {
binder.unlinkToDeath(linkedListener, 0 /* flags */);
}
return true;
}
用户主动调用removeListener。
---------------------
通过判断binder是否存活等也是一种简易的解决方案:
如:
在需要进行Callback的地方,进行判断:
Binder.isBinderAlive,代码如下
if (!jBinder.isBinderAlive()) {
// The hosting process of the provider has died; we can't
// use this one.
Log.i(TAG, "Acquiring provider " + auth + " for user " + userId
+ ": existing object's process dead");
//Do some thing
return null;
}
如果binder已经死亡,do something you want