- 上一篇中,在服务端的BookService中使用的是ArrayList,这是一个线程不安全的集合,因为AIDL的方法是在Binder的线程池中执行的,因此当多个客户端同时连接的时候,会存在多个线程同时访问的情况,所以我们要在AIDL方法中处理线程同步,下面使用一个新的集合类来代替它--CopyOnWriteArrayList
- CopyOnWriteArrayList
-
- 支持并发读/写
- 能自动进行线程同步
- 之前提到,AIDL中支持的List只有ArrayList,而我们用其对ArrayList进行替换,但CopyOnWriteArrayList不是继承自ArrayList。
- 虽然服务端返回的是一个CopyOnWriteArrayList,但是在Binder中会按照List的规范去访问数据并最终形成一个新的ArrayList传递给客户端,因此使用CopyOnWriteArrayList是完成可以的,同样的还有ConcurrentHashMap。
- 下面对该demo进行扩展,使用观察者模式,这样一种需求,用户不需要每次都去进行新书的获取,而是有新书的时候,主动去提醒进行订阅的用户,同样,用户也可以取消订阅。
-
- 首先,提供一个AIDL接口,每个用户都需要实现这个接口并向图书馆申请新书的提醒功能,之所以选择AIDL接口是因为AIDL中无法使用普通接口。
- 服务端
-
- 定义IOnNewBookArrivedListener.aidl,提供onNewBookArrived方法,如下:
// IONewBookArrivedListener.aidl package com.happy.ipc.server; import com.happy.ipc.server.domain.Book; // Declare any non-default types here with import statements interface IONewBookArrivedListener { void onNewBookArrived(in Book book); }
- 在IBookManager.aidl文件中添加注册和取消注册方法,如下:
// IBookManager.aidl package com.happy.ipc.server; import com.happy.ipc.server.domain.Book; import com.happy.ipc.server.IONewBookArrivedListener; // Declare any non-default types here with import statements interface IBookManager { int getBookCount(); List<Book> addBook(in Book book); void registerNewBookArrivedListener(IONewBookArrivedListener listener); void unRegisterNewBookArrivedListener(IONewBookArrivedListener listener); }
- 在BookService中实现这两个方法,如下:
@Override public void registerNewBookArrivedListener(IONewBookArrivedListener listener) throws RemoteException { if (listenerList.contains(listener)) { Log.i(TAG, "listener already existe"); } else { listenerList.add(listener); Log.i(TAG, "register listener succsss"); } } @Override public void unRegisterNewBookArrivedListener(IONewBookArrivedListener listener) throws RemoteException { if (listenerList.contains(listener)) { listenerList.remove(listener); Log.i(TAG, "unRegister listener success"); } else { Log.i(TAG, "not found listener"); } }
- 同时在BookService中开启一个线程,每隔五秒添加一本书,如下
private class WorkService implements Runnable { @Override public void run() { while (!mIsServiceDestoryed.get()) { try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } Book book = new Book(bookList.size() + 1, "new book" + bookList.size()); try { onNewBookArrived(book); } catch (RemoteException e) { e.printStackTrace(); } } } } private void onNewBookArrived(Book book) throws RemoteException { bookList.add(book); for (IONewBookArrivedListener listener : listenerList) { listener.onNewBookArrived(book); } }
- 定义IOnNewBookArrivedListener.aidl,提供onNewBookArrived方法,如下:
- 客户端
-
- 首先将刚才定义的aidl文件拷贝到客户端相同目录下
- 在绑定服务成功后,进行注册监听,如下
private IONewBookArrivedListener listener = new IONewBookArrivedListener.Stub() { @Override public void onNewBookArrived(Book book) throws RemoteException { Log.i(TAG, "onNewBookArrived : " + book.toString()); } }; private ServiceConnection conn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mBookManager = IBookManager.Stub.asInterface(service); try { mBookManager.registerNewBookArrivedListener(listener); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { mBookManager = null; } };
- 在onDestory方法中进行解绑监听和服务,如下:
@Override protected void onDestroy() { super.onDestroy(); if (mBookManager != null && mBookManager.asBinder().isBinderAlive()) { try { mBookManager.unRegisterNewBookArrivedListener(listener); } catch (RemoteException e) { e.printStackTrace(); } } unbindService(conn); }
- 通过log日志查看,发现达到预期,每隔五秒添加一本新书并通知客户端,并且可以进行监听的动态注册和解绑,如下:
- 但是,在activity关闭,进行注册监听解绑的时候,却发现log日志为
这是为什么呢,下篇进行讲述吧。
- 另外,服务端回调客户端的onBookArrived方法,是在客户端的Binder线程池中进行的,这里应该通过Handler将其发送到客户端的主线程中去执行,修改后代码如下:
private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case MESSAGE_BOOK_ARRIVED: Log.i(TAG, "onNewBookArrived : " + msg.obj.toString()); break; } } }; private IONewBookArrivedListener listener = new IONewBookArrivedListener.Stub() { @Override public void onNewBookArrived(Book book) throws RemoteException { mHandler.obtainMessage(MESSAGE_BOOK_ARRIVED, book).sendToTarget(); } };
IPC机制---04 Android中的IPC通讯方式(C)
最新推荐文章于 2025-03-06 21:56:01 发布