RemoteCallbackList 是 Android 提供的专门管理跨进程回调的容器。继续修改下RemoteService,使用RemoteCallbackList管理跨进程回调,替换掉那个ArrayList的callback容器。RemoteService代码如下:
java
package com.example.binderdemo;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
public class RemoteService extends Service {
private static final String TAG = "RemoteService";
// private final List<ICallback> callbacks = new ArrayList<>();
private final android.os.RemoteCallbackList<ICallback> callbacks =
new android.os.RemoteCallbackList<>();
private final android.os.Handler handler =
new android.os.Handler(android.os.Looper.getMainLooper());
private final Runnable tick = new Runnable() {
@Override
public void run() {
int n = callbacks.beginBroadcast();
Log.d(TAG, "tick, callbacks.size=" + n);
Log.d(TAG, "tick, callbacks.size=" + n + ", 何以解忧,唯有退休?");
try {
for (int i = 0; i < n; i++) {
ICallback cb = callbacks.getBroadcastItem(i);
try {
cb.onResult(9527);
} catch (RemoteException e) {
Log.e(TAG, "tick onResult failed: " + e);
}
}
} finally {
callbacks.finishBroadcast();
}
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();
}
private final IMyAidlInterface.Stub binder = new IMyAidlInterface.Stub() {
@Override
public int add(int a, int b) throws RemoteException {
Log.d(TAG, "add(" + a + "," + b + ") thread="
+ Thread.currentThread().getName()
+ ", pid=" + Process.myPid());
int result = a + b;
// 遍历回调:beginBroadcast / getBroadcastItem / finishBroadcast
int n = callbacks.beginBroadcast();
try {
for (int i = 0; i < n; i++) {
ICallback cb = callbacks.getBroadcastItem(i);
try {
cb.onResult(result);
} catch (RemoteException e) {
Log.e(TAG, "onResult failed: " + e);
}
}
} finally {
callbacks.finishBroadcast();
}
return result;
}
@Override
public String getMessage() {
Log.d(TAG, "getMessage thread="
+ Thread.currentThread().getName()
+ ", pid=" + Process.myPid());
return "Hello from pid=" + Process.myPid() + " , 为人不识陈近南,纵称英雄也枉然。";
}
@Override
public void registerCallback(ICallback cb) throws RemoteException {
if (cb == null) return;
Log.d(TAG, "registerCallback cb=" + cb
+ ", class=" + cb.asBinder().getClass().getName()
+ ", thread=" + Thread.currentThread().getName());
callbacks.register(cb);
}
@Override
public void unregisterCallback(ICallback cb) throws RemoteException {
if (cb != null) {
callbacks.unregister(cb);
}
}
};
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind thread="
+ Thread.currentThread().getName()
+ ", pid=" + Process.myPid());
return binder;
}
}
运行,查看日志:

点击杀客户端进程按钮,日志:


可以看出,使用RemoteCallbackList管理callback比较方便,其内部还兼顾了线程同步。而且客户端进程被杀掉后,服务端自动清理callback。callbacks.size 自动变 0,不需要写 binderDied,RemoteCallbackList 内部已经 linkToDeath 了。没有任何 DeadObjectException,因为死回调在 tick 遍历之前已经被移除了。没有 ConcurrentModificationException,beginBroadcast / finishBroadcast 的遍历快照机制生效了。onDestroy 在 60 秒后出现,这是后台服务限制,和 Binder 无关。比手动维护一个callback数组很有优势。
ok.