在Binder机制中有客户端和服务端。通过定义AIDL文件,客户端可以拿到服务端的IBinder接口,从而直接调用服务端的AIDL方法;而服务端同样可以通过回调的方式,拿到客户端的AIDL方法进行回调。
所有的AIDL方法都是在服务端的Binder线程池中执行的,也就是说,每一个AIDL方法执行的时候都会在一个服务线程中执行。
比如,客户端(Activity)通过ServiceConnection拿到了服务端(一般是service)的IBookManager这个AIDL接口:
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// 绑定成功后将Binder对象转换成AIDL接口
IBookManager bookManager = IBookManager.Stub.asInterface(service);
try {
mRemoteBookManager = bookManager;
BookEntity bookEntity = new BookEntity("3", "Android AIDL");
bookManager.addBook(bookEntity);
List<BookEntity> list = bookManager.getBookList();
for (BookEntity book : list) {
Logger.d(book.getBookId() + "," + book.getBookName());
}
bookManager.registerListener(mNewBookArrivedListener);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
mRemoteBookManager = null;
}
};
同时通过这个接口向服务端注册了一个回调AIDL接口:NewBookArrivedListener
客户端通过IbookManager接口发起一次调用,消息发送到Binder驱动,客户端当前处理这个调用的线程(及主线程)被挂起,Binder驱动通知服务端执行这个任务,一旦服务端执行这个任务时间过长(也就是客户端被挂起的时间过长),那么就可能导致客户端出现了ANR(在主线程中执行时间过长)。服务端执行完任务后,返回结果给Binder驱动,Binder驱动唤醒客户端线程继续处理。
服务端(service)通过AIDL回调接口,主动通知客户端(即回调客户端的AIDL接口的方法),该方法会执行在客户端的一个新起的线程中(并不在UI线程),所以此时要更新UI操作,就要切换线程了。(不是很理解为什么新开了一个线程?)
另外,在服务端数据集合一般使用CopyOnWriteArrayList,该类是线程安全的。因为服务端是用一个Binder线程池来处理客户端的各种请求,会存在多个客户端同时访问服务端的情况,数据集合必须实现线程同步。