继续上一篇 Binder双向通信-CSDN博客 , 修改下demo,RemoteService加一个定时器,服务端进程的主线程每3秒调用一下callback的onResult。增加的这段代码如下:
java
private final android.os.Handler handler =
new android.os.Handler(android.os.Looper.getMainLooper());
private final Runnable tick = new Runnable() {
@Override
public void run() {
Log.d(TAG, "tick, callbacks.size=" + callbacks.size());
for (ICallback cb : callbacks) {
try {
cb.onResult(999);
Log.d(TAG, "tick onResult success. \n不错!我就是美貌与智慧并重,英雄与侠义的化身唐伯虎");
} catch (RemoteException e) {
Log.e(TAG, "tick onResult failed: " + e);
}
}
handler.postDelayed(this, 3000);
}
};
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate, start tick");
handler.postDelayed(tick, 3000);
}
@Override
public void onDestroy() {
Log.d(TAG, "onDestroy, stop tick");
handler.removeCallbacks(tick);
super.onDestroy();
}
另外,MainActivity增加一个杀进程按钮,能杀掉客户端进程:

运行:

点击杀进程按钮,日志:

服务端 onDestroy, stop tick 说明:客户端进程被杀掉后,AMS 把绑定关系解除了,而RemoteService 只被 bindService 启动,没有 startService 的"启动标记",所以最后一个绑定客户端断开时,系统直接销毁了 Service。
再改下代码,先启动service,再绑定:

再运行,运行个几秒点击杀进程按钮,看下日志:

右日志可见, 服务端没有 onDestroy,tick 继续跑,每次调用回调都抛 DeadObjectException,而 callbacks.size 始终是 1。
服务端手里的 cb 是 ICallbackStubProxy,内部 mRemote 是 BinderProxy,BinderProxy 内部保存的是客户端 callback 的 handle。
客户端进程被 killProcess 杀掉后,Binder 驱动会清理这个进程的所有 Binder 对象。服务端那个 handle 指向的 binder_node 已经不存在了,handle 变成失效句柄。
服务端再调用 cb.onResult(999) 时,BinderProxy.transact 进入驱动,驱动发现 handle 对应的对象已经死了,直接返回错误 DeadObjectException。
handle 还在,但它指向的远端 Binder 已经没了。
callbacks.size一直是1,是因为callbacks是用的普通的arrayList,它不知道binder对象的生命周期。导致死回调永远留在列表里。如果多个客户端反复连接、死亡,列表会无限增长。