您的位置:首页 > 移动开发 > Android开发

IPC机制---04 Android中的IPC通讯方式(C)

2016-03-10 11:12 387 查看
上一篇中,在服务端的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);
}
}


客户端

首先将刚才定义的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();
}
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: