• 进程间的对话——aidl(二)


       上一节 http://www.cnblogs.com/fishbone-lsy/p/5327500.html 主要记录了一个跨进程的图片管理后台,设计了getBookList和addBook两个方法。但不管哪个方法,其实都是客户端对服务端发消息,然后服务端返回消息。没有服务端主动向客户端发消息的情况。所以,在这一节补充一下这种情况。增加一个新书通知的功能。

    所谓服务端给客户端发消息,其实质,还是客户端伸给服务端一个接口,服务端在要给客户端发消息时,就调用这个接口,让客户端监听到这一通知。这个接口是跨进程的,因此,我们还是需要用aidl来定义它。

    // IOnNewBookArrivedListener.aidl
    package com.dream.fishbonelsy.aidldemo.aidl;
    
    // Declare any non-default types here with import statements
    import com.dream.fishbonelsy.aidldemo.aidl.Book;
    
    interface IOnNewBookArrivedListener {
       void onNewBookArrived(in Book newBook);
    }

    然后,和上一节的顺序一样,先来写服务端它的实现。我们一个服务端可能同时为多个客户端服务,因此,服务端中可能保存了若干个客户端的接口。客户端决写了自己要不要将接口放入服务端,这其实是一个典型的观察者模式。

    因此,我们要在服务中,维护一个存放客户端接口的队列,并提供加入和移出这个队列的方法(即注册与注销)

    // BookManagerService.java
    public class BookManagerService extends Service {
    
        AtomicBoolean mIsServiceRunning = new AtomicBoolean(true);
        CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<Book>();
        RemoteCallbackList<IOnNewBookArrivedListener> mNewBookListenerList = new RemoteCallbackList<IOnNewBookArrivedListener>();
    
        private final IBookManager.Stub mBinder = new IBookManager.Stub() {
            @Override
            public List<Book> getBookList() throws RemoteException {
                synchronized (mBookList) {
                    return mBookList;
                }
            }
    
            @Override
            public void addBook(Book book) throws RemoteException {
                synchronized (mBookList) {
                    if (!mBookList.contains(book)) {
                        mBookList.add(book);
                        onNewBookArrived(book);
                    }
                }
            }
    
            @Override
            public void registerListener(IOnNewBookArrivedListener listener) throws RemoteException {
                mNewBookListenerList.register(listener);
    
            }
    
            @Override
            public void unregisterListener(IOnNewBookArrivedListener listener) throws RemoteException {
    
                mNewBookListenerList.unregister(listener);
    
            }
    
        };
    
        private void onNewBookArrived(Book book) throws RemoteException {
            int num = mNewBookListenerList.beginBroadcast();
            for( int  i=0; i < num ; i++){
                if (mNewBookListenerList.getBroadcastItem(i) != null){
                    mNewBookListenerList.getBroadcastItem(i).onNewBookArrived(book);
                }
            }
            mNewBookListenerList.finishBroadcast();
        }
    
    
        @Override
        public IBinder onBind(Intent intent) {
            return mBinder;
        }
    
        @Override
        public void onDestroy() {
            mIsServiceRunning.set(false);
            super.onDestroy();
        }
    }

    我们用一个RemoteCallbackList来存放来自其他进程的接口,它提供了register和unregister方法,我们只需要专注于给服务端发通知即可。

        private void onNewBookArrived(Book book) throws RemoteException {
            int num = mNewBookListenerList.beginBroadcast();
            for( int  i=0; i < num ; i++){
                if (mNewBookListenerList.getBroadcastItem(i) != null){
                    mNewBookListenerList.getBroadcastItem(i).onNewBookArrived(book);
                }
            }
            mNewBookListenerList.finishBroadcast();
        }

    RemoteCallbackList为了线程安全,一旦开始发送通知,就会把所有回调都上锁,因此,设计出开始发送和结束发送这样的结构。

    服务端的代码完成之后,客户端的依旧是比较容易。

      

        IOnNewBookArrivedListener onNewBookArrivedListener = new IOnNewBookArrivedListener.Stub() {
    
            @Override
            public void onNewBookArrived(Book newBook) throws RemoteException {
                Log.d("tag", "get the notify a new book has been added called ===" + newBook.bookName);
            }
        };
    
      mService.registerListener(onNewBookArrivedListener);

    定义接口,然后注册即可。

    值得注意的是,当我们把接口放在Activity中时,我们需要及时的注销接口,否则会导致内存泄露。

        @Override
        protected void onDestroy() {
            try {
                mService.unregisterListener(onNewBookArrivedListener);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
            unbindService(connection);
            super.onDestroy();
        }

    通过以上的代码,一个基本的跨进程通信过程算是完成。下一节会介绍一些一多对通信时,遇到的坑。

    Done~

  • 相关阅读:
    ELF和a.out文件格式的比较
    vim常用命令
    安装linux各种桌面环境
    使用virt-manager创建和管理虚拟机
    第一天 纪念一下
    i节点,容易被人遗忘的节点
    【Linux】服务器之间的免密登录脚本
    【python】python调用shell方法
    【ansible】ansible部署方式以及部署包
    【AWS】亚马逊云常用服务解释
  • 原文地址:https://www.cnblogs.com/fishbone-lsy/p/5331237.html
Copyright © 2020-2023  润新知