• 第二章 IPC


    Binder:
            这个博客讲的不错:

    通过AIDL来分析Binder跨进程通信的流程。
    假设服务端和客户端处在2个不同的进程当中,二者要实现跨进程通讯,则必须借助Binder。
    假设我们要传递的类为Book,则此类必须实现Parcelable的接口,实现序列化(这样才能进行跨进程的
    通讯)。
    然后编写AIDL指定一下方法,这些方法将成为跨进程通讯能调用的方法。

    再来看看服务端应该如何编写:
        
    1. //xxx是由AIDL自动生成的java类。,与AIDL文件名同名
    2. private final xxx.Stub Manager = new xxx.Stub() {
    3. //AIDL中定义的方法,我们在这里给出具体实现
    4. @Override
    5. public void AIDL中定义的方法(xxx xx) throws RemoteException {
    6. synchronized (this) {
    7. ...
    8. }
    9. }
    10. };
    11. public IBinder onBind(Intent intent) {
    12. return Manager;
    13. }


    我们看到,服务端通过AIDL自动生成的java类调用Stub方法生成一个Manager(Binder)然后在onBind方法中传递给客户端。
       
    接下来在看客户端的实现:
        
    1. private ServiceConnection mServiceConnection = new ServiceConnection() {
    2. @Override
    3. public void onServiceConnected(ComponentName name, IBinder service) {
    4. //其他略了,主要看这句,我们通过AIDL生成的xxxjava类的Stub.asInterface方法获得了
    5. Manager对象,可以使用这个对象进行进程间通讯了!
    6. Manager = xxx.Stub.asInterface(service);
    7. }
    8. @Override
    9. public void onServiceDisconnected(ComponentName name) {
    10. }
    11. };
    首先建立连接,然后在onServiceConnected方法中获取Manager对象
    1. 我们通过AIDL生成的xxxjava类的Stub.asInterface方法获得了Manager对象,可以使用这个对象进行进程间通讯了!

    这时便可以开始跨进程通讯了!

    然后再看客户端代码里,我们通过
    Manager = xxx.Stub.asInterface(service);
    来获取的Manager对象,首先分析一下asInterface是干什么的。
    1. public static com.lypeer.ipcclient.BookManager asInterface(android.os.IBinder obj) {
    2. //验空
    3. if ((obj == null)) {
    4. return null;
    5. }
    6. //DESCRIPTOR = "com.lypeer.ipcclient.BookManager",搜索本地是否已經
    7. //有可用的对象了,如果有就将其返回
    8. android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
    9. if (((iin != null) && (iin instanceof com.lypeer.ipcclient.BookManager))) {
    10. return ((com.lypeer.ipcclient.BookManager) iin);
    11. }
    12. //如果本地没有的话就新建一个返回
    13. return new com.lypeer.ipcclient.BookManager.Stub.Proxy(obj);
    14. }
    直接看最后一句,我们发现我们其实是通过
    asInterface(service)中的这个service生成的Manager对象。但是从源码中看到asInterface这个方法通过Proxy对这个service进行了代理

    再来分析一下Proxy(说明一下BookManager就是上文中用xxx代替的ADIL的文件名)
    1. private static class Proxy implements com.lypeer.ipcclient.BookManager {
    2. private android.os.IBinder mRemote;
    3. Proxy(android.os.IBinder remote) {
    4. //此处的 remote 正是前面我们提到的 IBinder service
    5. mRemote = remote;
    6. }
    7. //这里重载的方法就是我们在ADIL中定义的方法。
    8. @Override
    9. public java.util.List<com.lypeer.ipcclient.Book> getBooks() throws android.os.RemoteException {
    10. //很容易可以分析出来,_data用来存储流向服务端的数据流,
    11. //_reply用来存储服务端流回客户端的数据流
    12.     //_data其实是方法的入参,_reply其实是方法的返回值
    13. android.os.Parcel _data = android.os.Parcel.obtain();
    14. android.os.Parcel _reply = android.os.Parcel.obtain();
    15. java.util.List<com.lypeer.ipcclient.Book> _result;
    16. try {
    17. _data.writeInterfaceToken(DESCRIPTOR);
    18. //调用 transact() 方法将方法id和两个 Parcel 容器传过去
    19. mRemote.transact(Stub.TRANSACTION_getBooks, _data, _reply, 0);
    20. _reply.readException();
    21. //从_reply中取出服务端执行方法的结果
    22. _result = _reply.createTypedArrayList(com.lypeer.ipcclient.Book.CREATOR);
    23. } finally {
    24. _reply.recycle();
    25. _data.recycle();
    26. }
    27. //将结果返回
    28. return _result;
    29. }
    30. @Override
    31. public void addBook(com.lypeer.ipcclient.Book book) throws android.os.RemoteException {
    32. //省略
    33. }
    34. //省略部分方法
    35. }

    _data其实是方法的入参,_reply其实是方法的返回值,
    注意到这一句,Proxy这个类在这个方法中调用了transact方法,这肯定是和服务器交互的方法没跑了!
    mRemote.transact(Stub.TRANSACTION_getBooks, _data, _reply, 0);
    1. 关于 transact() 方法:这是客户端和服务端通信的核心方法。调用这个方法之后,客户端将会挂起当前线程,等候服务端执行完相关任务后通知并接收返回的 _reply 数据流。
    好!现在已经明了了客户端与服务器交互的流程了!
    首先在建立连接的时候,onServiceConnected的方法中会获取到服务端的service(Binder对象),
    然后通过AIDL生成的Manager接口的asInterface方法传入service获取Manager对象。
    而asInterface内部则通过返回一个代理类(继承了AIDL生成的Manager接口的类)为Manager对象。
    在这个代理类中封装了与服务器交换数据的方法。


    那么服务端如何获取传递过来的数据呢?我们看到由AIDL生成的java类中有这个方法
    1. @Override
    2. public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
    3. switch (code) {
    4. case INTERFACE_TRANSACTION: {
    5. reply.writeString(DESCRIPTOR);
    6. return true;
    7. }
    8. case TRANSACTION_getBooks: {
    9. data.enforceInterface(DESCRIPTOR);
    10. //调用 this.getBooks() 方法,在这里开始执行具体的事务逻辑
    11. //result 列表为调用 getBooks() 方法的返回值
    12. java.util.List<com.lypeer.ipcclient.Book> _result = this.getBooks();
    13. reply.writeNoException();
    14. //将方法执行的结果写入 reply ,
    15. reply.writeTypedList(_result);
    16. return true;
    17. }
    18. case TRANSACTION_addBook: {
    19. //省略
    20. return true;
    21. }
    22. }
    23. return super.onTransact(code, data, reply, flags);
    24. }
    非常的简单直了,直接调用服务端这边的具体方法实现,然后获取返回值并将其写入 reply 流。

    我们总结一下服务端的一般工作流程:

    • 1,获取客户端传过来的数据,根据方法 ID 执行相应操作。
    • 2,将传过来的数据取出来,调用本地写好的对应方法。
    • 3,将需要回传的数据写入 reply 流,传回客户端。

    到此则分析完毕了。

    隐藏了具体的细节,但是流程还是很详细的,以下是流程图,加深理解

     



    使用文件进行进程间通讯:
        利用序列化对象将对象写入文件,然后另一个进程进行读取。需要一定的同步机制。
        不能用sharedPerfence,因为它会在内存中存有一个缓存,出错的可能性很大。


    使用Messenger
        一种轻量级别的IPC方案。底层实现是AIDL。
    不进行仔细的介绍了。相信通过代码能很快理解。

    服务端:
    1. private static class MessengerHandler extends Handler {
    2. @Override
    3. public void handleMessage(Message msg) {
    4. switch (msg.what) {
    5. case MyConstants.MSG_FROM_CLIENT:
    6. Log.i(TAG, "receive msg from Client:" + msg.getData().getString("msg"));
    7. Messenger client = msg.replyTo;
    8. Message relpyMessage = Message.obtain(null, MyConstants.MSG_FROM_SERVICE);
    9. Bundle bundle = new Bundle();
    10. bundle.putString("reply", "嗯,你的消息我已经收到,稍后会回复你。");
    11. relpyMessage.setData(bundle);
    12. try {
    13. client.send(relpyMessage);
    14. } catch (RemoteException e) {
    15. e.printStackTrace();
    16. }
    17. break;
    18. default:
    19. super.handleMessage(msg);
    20. }
    21. }
    22. }
    首先编写一个Hanlder处理消息。
    然后根据这个Hanlder生成一个Messenger对象,最后将Binder返回即可。
    1. private final Messenger mMessenger = new Messenger(new MessengerHandler());
    2. @Override
    3. public IBinder onBind(Intent intent) {
    4. return mMessenger.getBinder();
    5. }

    客户端:
    因为要接收服务端的信息,所以也需要创建一个Messager,要创建一个Messager先创建处理信息的Handler
    1. private static class MessengerHandler extends Handler {
    2. @Override
    3. public void handleMessage(Message msg) {
    4. switch (msg.what) {
    5. case MyConstants.MSG_FROM_SERVICE:
    6. Log.i(TAG, "receive msg from Service:" + msg.getData().getString("reply"));
    7. break;
    8. default:
    9. super.handleMessage(msg);
    10. }
    11. }
    12. }
    然后在onServiceConnected方法中处理即可
    1. private ServiceConnection mConnection = new ServiceConnection() {
    2. public void onServiceConnected(ComponentName className, IBinder service) {
    3. mService = new Messenger(service);
    4. Log.d(TAG, "bind service");
    5. Message msg = Message.obtain(null, MyConstants.MSG_FROM_CLIENT);
    6. Bundle data = new Bundle();
    7. data.putString("msg", "hello, this is client.");
    8. msg.setData(data);
    9. msg.replyTo = mGetReplyMessenger;
    10. try {
    11. mService.send(msg);
    12. } catch (RemoteException e) {
    13. e.printStackTrace();
    14. }
    15. }
    16. public void onServiceDisconnected(ComponentName className) {
    17. }
    18. };



    AIDL:
        上面介绍Binder运行流程的时候已经有了大概的介绍了。下面我们来说一个《观察者模式》
     既当有新内容的时候,由服务端发送消息给客户端。
    之前的例子都是服务端返回Binder而客户端进行调用。其实我们可以通过将客户端的Binder利用服务端Binder实现的方法发给服务端,
    从而实现服务端发送消息给客户端。

      如这个AIDL所示,里面的接口方法中包含了绑定和接触绑定(用于向服务端传递Binder)。
    1. package com.ryg.chapter_2.aidl;
    2. import com.ryg.chapter_2.aidl.Book;
    3. import com.ryg.chapter_2.aidl.IOnNewBookArrivedListener;
    4. interface IBookManager {
    5. List<Book> getBookList();
    6. void addBook(in Book book);
    7. void registerListener(IOnNewBookArrivedListener listener);
    8. void unregisterListener(IOnNewBookArrivedListener listener);
    9. }
    然后服务端去实现这个AIDL的方法:
        
    1. private Binder mBinder = new IBookManager.Stub() {
    2. @Override
    3. public List<Book> getBookList() throws RemoteException {
    4. SystemClock.sleep(5000);
    5. return mBookList;
    6. }
    7. @Override
    8. public void addBook(Book book) throws RemoteException {
    9. mBookList.add(book);
    10. }
    11. @Override
    12. public void registerListener(IOnNewBookArrivedListener listener)
    13. throws RemoteException {
    14. mListenerList.register(listener);
    15. final int N = mListenerList.beginBroadcast();
    16. mListenerList.finishBroadcast();
    17. Log.d(TAG, "registerListener, current size:" + N);
    18. }
    19. @Override
    20. public void unregisterListener(IOnNewBookArrivedListener listener)
    21. throws RemoteException {
    22. boolean success = mListenerList.unregister(listener);
    23. if (success) {
    24. Log.d(TAG, "unregister success.");
    25. } else {
    26. Log.d(TAG, "not found, can not unregister.");
    27. }
    28. final int N = mListenerList.beginBroadcast();
    29. mListenerList.finishBroadcast();
    30. Log.d(TAG, "unregisterListener, current size:" + N);
    31. };
    32. };
    其中mListenerList是RemoteCallBackList
    private RemoteCallbackList<IOnNewBookArrivedListener> mListenerList = new RemoteCallbackList<IOnNewBookArrivedListener>();
            至于为么用RemoteCallbackList而不用普通的List参看android开发艺术探索第88页附近。

              然后在客户端里绑定即可。
    1. private ServiceConnection mConnection = new ServiceConnection() {
    2. public void onServiceConnected(ComponentName className, IBinder service) {
    3. IBookManager bookManager = IBookManager.Stub.asInterface(service);
    4. mRemoteBookManager = bookManager;
    5. try {
    6. mRemoteBookManager.asBinder().linkToDeath(mDeathRecipient, 0);
    7. List<Book> list = bookManager.getBookList();
    8. Log.i(TAG, "query book list, list type:"
    9. + list.getClass().getCanonicalName());
    10. Log.i(TAG, "query book list:" + list.toString());
    11. Book newBook = new Book(3, "Android进阶");
    12. bookManager.addBook(newBook);
    13. Log.i(TAG, "add book:" + newBook);
    14. List<Book> newList = bookManager.getBookList();
    15. Log.i(TAG, "query book list:" + newList.toString());
    16. bookManager.registerListener(mOnNewBookArrivedListener);
    17. } catch (RemoteException e) {
    18. e.printStackTrace();
    19. }
    20. }
    21. public void onServiceDisconnected(ComponentName className) {
    22. mRemoteBookManager = null;
    23. Log.d(TAG, "onServiceDisconnected. tname:" + Thread.currentThread().getName());
    24. }
    25. };
    26. private IOnNewBookArrivedListener mOnNewBookArrivedListener = new IOnNewBookArrivedListener.Stub() {
    27. @Override
    28. public void onNewBookArrived(Book newBook) throws RemoteException {
    29. mHandler.obtainMessage(MESSAGE_NEW_BOOK_ARRIVED, newBook)
    30. .sendToTarget();
    31. }
    32. };

      注意:虽然mOnNewBookArrivedListener 传递给服务端的时候,因为序列化的原因所以服务端的mOnNewBookArrivedListener 
    虽然和客户端的一模一样,但是其实已经不是同一个了,但是它们底层的Binder对象是同一个,所以还是能正常调用。

       

    AIDL补充:Binder连接池
        http://blog.csdn.net/u012760183/article/details/51397014
    http://www.2cto.com/kf/201604/499360.html




    一下是博客的内容:


    一、 前言

    在上一篇文章 Android IPC机制(三):浅谈Binder的使用中,笔者浅谈了Binder的使用及其工作机制,利用AIDL方式能很方便地进行客户端和服务端的跨进程通信。但是,我们想一下,如果按照我们之前的使用方法,必须满足一个AIDL接口对应一个service,那么问题来了,假如我们的应用,有很多模块,而每一个模块都需要和服务端通讯,那么我们也要为每一个模块创建特定的aidl文件,那么服务端service也会产生很多个,显然,如果aidl接口变多,那么service也会跟着变多,那么这样的用户体验就会非常不好,那么我们该怎么做呢?在任玉刚著的《Android 开发艺术探索》一书中,给出了一个Binder连接池的概念,即利用一个Binder连接池来管理所有Binder,服务端只需要管理这个Bindere连接池即可,这样就能实现一个service管理多个Binder,为不同的模块返回不同的Binder,以实现进程间通讯。所以,本文将讲述如何实现Binder连接池。


    二、实现

    1、先提供两个AIDL接口来模拟多个模块都要使用AIDL的情况:ISpeak接口和ICalculate接口:

    1
    2
    3
    4
    package com.chenyu.service;
    interface ISpeak {
        void speak();
    }

    1
    2
    3
    4
    package com.chenyu.service;
    interface ICalculate {
        int add(in int num1,in int num2);
    }


    接着,实现这两个接口:分别为Speak.java和Calculate.java文件:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public class Speak extends Stub {
        public Speak() {
            Log.d("cylog","我被实例化了..............");
        }
        @Override
        public void speak() throws RemoteException {
            int pid = android.os.Process.myPid();
            Log.d("cylog","当前进程ID为:"+pid+"-----"+"这里收到了客户端的speak请求");
        }
    }

    1
    2
    3
    4
    5
    6
    7
    8
    public class Calculate extends ICalculate.Stub {
        @Override
        public int add(int num1, int num2) throws RemoteException {
            int pid = android.os.Process.myPid();
            Log.d("cylog", "当前进程ID为:"+pid+"----"+"这里收到了客户端的Calculate请求");
            return num1+num2;
        }
    }


    1
     
    可以看到,这两个接口的实现类,都是继承了Interface.Stub类,这个在上一章的服务端代码出现过,是在服务端的service内部实现了接口的方法,而这里我们把实现了接口的方法从服务端抽离出来了,其实这个实现类依然是运行在服务端的进程中,从而实现了AIDL接口和服务端的解耦合工作,让服务端不再直接参与AIDL接口方法的实现工作。那么,服务端通过什么桥梁与AIDL接口联系呢?答案就是Binder连接池。Binder连接池管理着所有的AIDL接口,就如一位将军统帅着千军。客户端需要什么Binder,就提供信息给Binder连接池,而连接池根据相应信息返回正确的Binder,这样客户端就能执行特定的操作了。可以说,Binder连接池的思路,非常类似设计模式之中的工厂模式。接下来我们看Binder连接池的具体实现:

    2、为Binder连接池创建AIDL接口:IBinderPool.aidl:

    1
    2
    3
    interface IBinderPool {
        IBinder queryBinder(int binderCode);  //查找特定Binder的方法
    }

    为什么需要这个接口?我们从上面的分析可以知道,service端并不直接提供具体的Binder,那么客户端和服务端连接的时候就应该返回一个IBinderPool对象,让客户端拿到这个IBinderPool的实例,然后由客户端决定应该用哪个Binder。所以服务端的代码很简单,只需要返回IBinderPool对象即可:


    3、服务端service代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public class BinderPoolService extends Service {
     
        private Binder mBinderPool = new BinderPool.BinderPoolImpl();   // 1
        private int pid = Process.myPid();
        @Override
        public IBinder onBind(Intent intent) {
            Log.d("cylog", "当前进程ID为:"+pid+"----"+"客户端与服务端连接成功,服务端返回BinderPool.BinderPoolImpl 对象");
            return mBinderPool;
        }
    }

    ①号代码处,实例化了一个BinderPool.BinderPoolImpl类,并在onBind方法返回了这个mBinderPool对象。


    4、接下来我们看BinderPool的具体实现,代码比较长,我们先大体上认识,再详细分析:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    public class BinderPool {
        public static final int BINDER_SPEAK = 0;
        public static final int BINDER_CALCULATE = 1;
     
        private Context mContext;
        private IBinderPool mBinderPool;
        private static volatile BinderPool sInstance;
        private CountDownLatch mConnectBinderPoolCountDownLatch;
     
        private BinderPool(Context context) {<span style="white-space:pre"> </span>   // 1
            mContext = context.getApplicationContext();
            connectBinderPoolService();
        }
     
        public static BinderPool getInstance(Context context) {     // 2
            if (sInstance == null) {
                synchronized (BinderPool.class) {
                    if (sInstance == null) {
                        sInstance = new BinderPool(context);
                    }
                }
            }
            return sInstance;
        }
     
        private synchronized void connectBinderPoolService() {      // 3
            mConnectBinderPoolCountDownLatch = new CountDownLatch(1);
            Intent service = new Intent(mContext, BinderPoolService.class);
            mContext.bindService(service, mBinderPoolConnection,
                    Context.BIND_AUTO_CREATE);
            try {
                mConnectBinderPoolCountDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
         
        public IBinder queryBinder(int binderCode) {          // 4
            IBinder binder = null;
            try {
                if (mBinderPool != null) {
                    binder = mBinderPool.queryBinder(binderCode);
                }
            } catch (RemoteException e) {
                e.printStackTrace();
            }
            return binder;
        }
     
        private ServiceConnection mBinderPoolConnection = new ServiceConnection() {       // 5
     
            @Override
            public void onServiceDisconnected(ComponentName name) {
                 
            }
     
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                mBinderPool = IBinderPool.Stub.asInterface(service);
                try {
                    mBinderPool.asBinder().linkToDeath(mBinderPoolDeathRecipient, 0);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                mConnectBinderPoolCountDownLatch.countDown();
            }
        };
     
        private IBinder.DeathRecipient mBinderPoolDeathRecipient = new IBinder.DeathRecipient() {    // 6
            @Override
            public void binderDied() {
                mBinderPool.asBinder().unlinkToDeath(mBinderPoolDeathRecipient, 0);
                mBinderPool = null;
                connectBinderPoolService();
            }
        };
     
        public static class BinderPoolImpl extends IBinderPool.Stub {     // 7
     
            public BinderPoolImpl() {
                super();
            }
     
            @Override
            public IBinder queryBinder(int binderCode) throws RemoteException {
                IBinder binder = null;
                switch (binderCode) {
                    case BINDER_SPEAK: {
                        binder = new Speak();
                        break;
                    }
                    case BINDER_CALCULATE: {
                        binder = new Calculate();
                        break;
                    }
                    default:
                        break;
                }
     
                return binder;
            }
        }
     
    }

    大体上看,这个类完成的功能有实现客户端和服务端的连接,同时内有还有一个静态内部类:BinderPoolImpl,继承了IBinderPool.Stub,这也非常眼熟,所以这个静态内部类应该是运行了服务端的。好了,我们从上往下分析每一个方法的作用:

    ①private BinderPool(Context context)构造方法:这里传递了context对象,注意到,这个构造方法使用了private修饰,那么外界是无法直接调用构造器的,所以有了②号方法。


    ②public static BinderPool getInstance(Context context):看到getInstance字样,熟悉设计模式的读者应该知道了这里是使用了单例模式,而且是线程同步的懒汉式单例模式,在方法内部,把传递进来的context上下文参数传递进构造函数,即此时调用了①号方法,接着①号方法调用了connectBinderPoolService()方法,即③号方法。


    ③private synchronized void connectBinderPoolService():这个方法主要用于客户端与服务端建立连接,在方法内部出现了CountDownLatch类,这个类是用于线程同步的,由于bindService()是异步操作,所以如果要确保客户端在执行其他操作之前已经绑定好服务端,就应该先实现线程同步。这里简单提一下这个类:

    CountDownLatch类有三个主要方法:

    (1)构造方法 CountDownLatch(int num):这里传递一个num值,为countdownlatch内部的计时器赋值。

    (2)countdown():每当调用一次这个方法,countdownlatch实例内部计时器数值 - 1。

    (3)await():让当前线程等待,如果内部计时器变为0,那么唤醒当前线程。


    ④public IBinder queryBinder(int binderCode):根据具体的binderCode值来获得某个特定的Binder,并返回。


    ⑤private ServiceConnection mBinderPoolConnection = new ServiceConnection(){} :这个类似于上一章客户端的连接代码,在服务端与客户端连接成功的时候,会回调当前的onServiceConnected()函数,我们来着重看看这个函数:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                mBinderPool = IBinderPool.Stub.asInterface(service);
                try {
                    mBinderPool.asBinder().linkToDeath(mBinderPoolDeathRecipient, 0);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                mConnectBinderPoolCountDownLatch.countDown();
            }

    注意到,方法内部执行了mBinderPool = IBinderPool.Stub.asInterface(service)方法,由上一章的分析可知,这里的mBinderPool实际上是IBinderPool的一个代理对象,即此时客户端获得了服务端Binder连接池的一个代理对象。

    接着,最后执行了mConnectBinderPoolCountDownLatch.countDown()方法,此时,执行bindService()的线程就会被唤醒。


    ⑥private IBinder.DeathRecipient mBinderPoolDeathRecipient = new IBinder.DeathRecipient(){}:为IBinder设置死亡监听,如果连接意外中断,会自动重新连接。


    ⑦public static class BinderPoolImpl extends IBinderPool.Stub{} :这个类实现了IBinderPool.Stub,内部实现了IBinderPool的接口方法,这个实现类运行在服务端。内部是queryBinder()方法的实现,根据不同的Bindercode值来实例化不同的实现类,比如Speak或者Calculate,并作为Binder返回给客户端。当客户端调用这个方法的时候,实际上已经是进行了一次AIDL方式的跨进程通信。

    5、分析完BinderPool代码,最后,我们实现客户端代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    package com.chenyu.binderpool;
    import android.app.Activity;
    import android.os.*;
    import android.util.Log;
     
    import com.chenyu.service.BinderPool;
    import com.chenyu.service.Calculate;
    import com.chenyu.service.ICalculate;
    import com.chenyu.service.ISpeak;
    import com.chenyu.service.Speak;
     
    public class MainActivity extends Activity {
     
        private ISpeak mSpeak;
        private ICalculate mCalculate;
        private int pid = android.os.Process.myPid();
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            new Thread(new Runnable() {
                @Override
                public void run() {
                    startWork();
                }
            }).start();
        }
     
        private void startWork() {
            Log.d("cylog","当前进程ID为:"+pid);
            Log.d("cylog","获取BinderPool对象............");
            BinderPool binderPool = BinderPool.getInsance(MainActivity.this);     // 1
            Log.d("cylog","获取speakBinder对象...........");
            IBinder speakBinder = binderPool.queryBinder(BinderPool.BINDER_SPEAK);  // 2
            Log.d("cylog","获取speak的代理对象............");
            mSpeak = (ISpeak) ISpeak.Stub.asInterface(speakBinder);    // 3
            try {
                mSpeak.speak();     // 4
            } catch (RemoteException e) {
                e.printStackTrace();
            }
            Log.d("cylog","获取calculateBinder对象...........");
            IBinder calculateBinder = binderPool.queryBinder(BinderPool.BINDER_CALCULATE);
            Log.d("cylog","获取calculate的代理对象............");
            mCalculate = (ICalculate) ICalculate.Stub.asInterface(calculateBinder);
            try {
                Log.d("cylog",""+mCalculate.add(5,6));
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
     
    }


    由于跨进程通信是耗时操作,这里利用了子线程来进行绑定以及请求等操作。这里简单分析一下从子线程开始,整个跨进程通讯流程是怎样的:
    首先,在①处,调用了BinderPool的getInstance()方法,在里面执行了绑定服务的操作,此时得到的binderPool是BinderPool对象。接着执行②号代码,调用BinderPool对象的queryBinder()方法,此时发生了AIDL跨进程请求,得到服务端返回的特定的IBinder对象。接着执行③号代码,调用ISpeak.Stub.asInterface(IBinder iBinder)方法,把刚才获得的IBinder对象传递进去,此时返回了Speak的Proxy代理对象。 最后执行④号代码,调用代理对象mSpeak的speak()方法,此时再次发生了AIDL跨进程请求,调用了服务端Speak类的speak方法。

    我们看一下运行结果:




    三、总结

    最后总结一下使用Binder连接池的流程:

    (1)为每个业务模块创建AIDL接口,以及实现其接口的方法。

    (2)创建IBinderPool.aidl文件,定义queryBinder(int BinderCode)方法,客户端通过调用该方法返回特定的Binder对象。

    (3)创建BinderPoolService服务端,在onBind方法返回实例化的BinderPool.IBinderPoolImpl对象。

    (4)创建BinderPool类,在该类实现客户端与服务端的连接,解决线程同步的问题,设置Binder的死亡代理等。在onServiceConnected()方法内,获取到IBinderPool的代理对象。此外,IBinderPool的实现类:IBinderPoolImpl是BinderPool的内部类,实现了IBinderPool.aidl的方法:queryBinder()。










  • 相关阅读:
    Coursera《machine learning》--(8)神经网络表述
    应该如何入门deep learning呢?从UFLDL开始!
    Coursera《machine learning》--(2)单变量线性回归(Linear Regression with One Variable)
    判断当前终端是手机还是pc端并进行不同的页面跳转
    html5实现拖拽上传
    swiper和tab相结合
    懒加载
    网页分享各平台
    文本框输入内容自动提示效果
    给当前选中分类加背景色
  • 原文地址:https://www.cnblogs.com/You0/p/5984463.html
Copyright © 2020-2023  润新知