AIDL基本使用(二)
将观察者模式和AIDL结合起来使用,使用RemoteCallBackList管理跨进程的接口。普通接口由于使用Binder传输需要序列化和反序列化,每次客户端传递过来的都是一个新对象,无法做到解注册。而RemoteCallBackList内部使用ArrayMap,将接口和Binder对象匹配起来。
注:阅读本文章前请先阅读前一篇文章AIDL基本使用(一)
这里的观察者模式指的是客户端在服务端注册,服务端事件发生时通知客户端执行相应的事件。也就是客户端需要在服务端进行注册和解注册。本文紧接上篇文章,以图书馆(服务端)图书到来,通知客户端图书到来为例
操作步骤
1.跨进程的接口使用AIDL,所以先写一个aidl接口。
package com.example.xin.aidldemo;
import com.example.xin.aidldemo.Book;
interface IOnNewBookArrivedListener {
void onNewBookArrived(in Book book);
}
2.在IBookManager接口中新增注册和解注册两个方法。
package com.example.xin.aidldemo;
import com.example.xin.aidldemo.Book;
import com.example.xin.aidldemo.IOnNewBookArrivedListener;
interface IBookManager {
List<Book> getBookList();
void addBook(in Book book);
void registerListener(in IOnNewBookArrivedListener listener);
void unRegisterListener(IOnNewBookArrivedListener listener);
}
3.服务端实现注册和解注册,其实就是用一个RemoteCallBackList来存放注册进来的接口,当图书到达图书馆时,逐一调用这些接口的实现。图书到达图书馆这一行为用一个线程循环执行模拟。
public class BookManagerService extends Service {
private CopyOnWriteArrayList<Book> mBookList;
private RemoteCallbackList<IOnNewBookArrivedListener> mNewBookArrivedListenerList;
private boolean isDestroy = false;
private Binder mBinder = new IBookManager.Stub() {
@Override
public List<Book> getBookList() throws RemoteException {
Log.d("ZXX","getBookList Service");
return mBookList;
}
@Override
public void addBook(Book book) throws RemoteException {
mBookList.add(book);
}
@Override
public void registerListener(IOnNewBookArrivedListener listener) throws RemoteException {
//注册接口,将接口添加到RemoteCallBackList
mNewBookArrivedListenerList.register(listener);
}
@Override
public void unRegisterListener(IOnNewBookArrivedListener listener) throws RemoteException {
//解注册接口
mNewBookArrivedListenerList.unregister(listener);
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public void onCreate() {
mBookList = new CopyOnWriteArrayList<>();
mBookList.add(new Book(1,"测试"));
mBookList.add(new Book(2,"测试2"));
mNewBookArrivedListenerList = new RemoteCallbackList<>();
new Thread(new ServiceWorker()).start();
}
//图书到达图书馆就逐一通知客户端执行
private void newBookArrived(Book book){
mNewBookArrivedListenerList.beginBroadcast();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
for(int i = 0; i < mNewBookArrivedListenerList.getRegisteredCallbackCount(); i++){
IOnNewBookArrivedListener listener = mNewBookArrivedListenerList.getBroadcastItem(i);
if(listener != null){
try {
listener.onNewBookArrived(book);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
}
mNewBookArrivedListenerList.finishBroadcast();
}
@Override
public void onDestroy() {
super.onDestroy();
isDestroy = true;
}
//模拟图书到达图书馆
private class ServiceWorker implements Runnable{
@Override
public void run() {
while(!isDestroy){
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
int bookId = mBookList.size() + 1;
Log.e("ZXX","size: " + mBookList.size());
Book book = new Book(bookId, "测试"+bookId);
mBookList.add(book);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
newBookArrived(book);
}
}
}
}
}
4.客户端注册接口
public class MainActivity extends AppCompatActivity {
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
IBookManager bookManager = IBookManager.Stub.asInterface(iBinder);
try {
List<Book> list = bookManager.getBookList();
for(Book b : list){
Log.d("ZXX",b.getName());
}
//注册监听到服务端
bookManager.registerListener(mNewBookListener);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, BookManagerService.class);
bindService(intent,serviceConnection, Context.BIND_AUTO_CREATE);
}
//注意是AIDL接口,new的时候是new 一个Stub接口
private IOnNewBookArrivedListener mNewBookListener = new IOnNewBookArrivedListener.Stub() {
@Override
public void onNewBookArrived(Book book) throws RemoteException {
Log.e("ZXX",book.getName());
}
};
}
打出的Log:
08-09 23:24:20.722 23188-23188/com.example.xin.aidldemo D/ZXX: 测试
08-09 23:24:20.722 23188-23188/com.example.xin.aidldemo D/ZXX: 测试2
08-09 23:24:25.613 23188-23203/com.example.xin.aidldemo E/ZXX: 测试3
08-09 23:24:30.615 23188-23205/com.example.xin.aidldemo E/ZXX: 测试4
08-09 23:24:35.617 23188-23207/com.example.xin.aidldemo E/ZXX: 测试5
08-09 23:24:40.620 23188-23207/com.example.xin.aidldemo E/ZXX: 测试6