IPC机制--BinderPool

来源:互联网 发布:ios程序员烂大街 编辑:程序博客网 时间:2024/05/17 07:19

当很多模块都需要AIDL来进行跨进程通信,我们不可能为每一个AIDL创建Sevice,因此,我们可以采用BinderPool来托管我们的其他进程间通信接口,通过一些请求码对不同的进程间通信接口加以区分,在进行指定的进程间通信的时候,先从BinderPool中取出对应的Binder,利用其进行通信即可。利用这个方法,避免了多次创建Service,以及对系统资源的滥用,我们来看下如何实现BinderPo.ol机制。

首先,创建BinderPool的AIDL文件

// IBinderPool.aidlpackage com.example.no_clay.messagertest.BinderPool;// Declare any non-default types here with import statementsinterface IBinderPool {    IBinder queryBinder(int binderCode);}

其次,其他AIDL文件的创建和接口完善

// ISecurityCenter.aidlpackage com.example.no_clay.messagertest.BinderPool;// Declare any non-default types here with import statementsinterface ISecurityCenter {    String encrypt(String content);    String decrypt(String password);}// ICompute.aidlpackage com.example.no_clay.messagertest.BinderPool;// Declare any non-default types here with import statementsinterface ICompute {    int add(int a, int b);}

完善接口文件

package com.example.no_clay.messagertest.BinderPool;import android.os.RemoteException;/** * Created by no_clay on 2017/3/1. */public class ComputeImpl extends ICompute.Stub {    @Override    public int add(int a, int b) throws RemoteException {        return a + b;    }}package com.example.no_clay.messagertest.BinderPool;import android.os.RemoteException;/** * Created by no_clay on 2017/3/1. */public class SecurityCenterImpl extends ISecurityCenter.Stub {    private static final char SECRET_CODE = '^';    @Override    public String encrypt(String content) throws RemoteException {        char[] chars = content.toCharArray();        for (int i = 0; i < chars.length; i++) {            chars[i] ^= SECRET_CODE;        }        return new String(chars);    }    @Override    public String decrypt(String password) throws RemoteException {        return encrypt(password);    }}

接下来是对BinderPool接口的实现

package com.example.no_clay.messagertest.BinderPool;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.os.IBinder;import android.os.RemoteException;import android.util.Log;import java.util.concurrent.CountDownLatch;/** * Created by no_clay on 2017/3/1. */public class BinderPool {    private static final String TAG = "BinderPool";    //常量用于标志binder    public static final int BINDER_NONE = -1;    public static final int BINDER_COMPUTE = 0;    public static final int BINDER_SECURITY_CENTER = 1;    private Context mContext;    private IBinderPool mBinderPool;    //用于实现单例模式    private static volatile BinderPool sInstance;    //同步工具类    private CountDownLatch mConnectBinderPoolCountDownLatch;    private BinderPool(Context context) {        mContext = context.getApplicationContext();        //连接服务        connectBinderPoolService();    }    public static BinderPool getInstance(Context context) {        if (sInstance == null) {            synchronized (BinderPool.class) {                if (sInstance == null) {                    sInstance = new BinderPool(context);                }            }        }        return sInstance;    }    private synchronized void connectBinderPoolService() {        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();        }    }    private ServiceConnection mBinderPoolConnection = new ServiceConnection() {        @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();        }        @Override        public void onServiceDisconnected(ComponentName name) {        }    };    //死亡代理    private IBinder.DeathRecipient mBinderPoolDeathRecipient =            new IBinder.DeathRecipient() {                @Override                public void binderDied() {                    Log.w(TAG, "binderDied: ");                    mBinderPool.asBinder().unlinkToDeath(mBinderPoolDeathRecipient, 0);                    mBinderPool = null;                    connectBinderPoolService();                }            };    public static class BinderPoolImpl extends IBinderPool.Stub {        @Override        public IBinder queryBinder(int binderCode) throws RemoteException {            IBinder binder = null;            switch (binderCode) {                case BINDER_SECURITY_CENTER: {                    binder = new SecurityCenterImpl();                    break;                }                case BINDER_COMPUTE: {                    binder = new ComputeImpl();                    break;                }                default:                    break;            }            return binder;        }    }    /**     * query binder by binderCode from binder pool     * @param binderCode     * @return     */    public IBinder queryBinder(int binderCode) {        IBinder binder = null;        Log.d(TAG, "queryBinder: binderPool = " + (mBinderPool == null));        try {            if (mBinderPool != null) {                binder = mBinderPool.queryBinder(binderCode);            }        } catch (RemoteException e) {            e.printStackTrace();        }        return binder;    }}

CountDownLatch

  1. 实现最大的并行性:有时我们想同时启动多个线程,实现最大程度的并行性。例如,我们想测试一个单例类。如果我们创建一个初始计数为1的CountDownLatch,并让所有线程都在这个锁上等待,那么我们可以很轻松地完成测试。我们只需调用 一次countDown()方法就可以让所有的等待线程同时恢复执行。
  2. 开始执行前等待n个线程完成各自任务:例如应用程序启动类要确保在处理用户请求前,所有N个外部系统已经启动和运行了。
  3. 死锁检测:一个非常方便的使用场景是,你可以使用n个线程访问共享资源,在每次测试阶段的线程数目是不同的,并尝试产生死锁。

总结

这样以来我们就能在我们的应用中只建立一个Service就足够了。当我们添加一个AIDL接口的时候只需要在BinderPool中添加一个id,然后根据这个id,在BinderPoolImpl中创建一个对应的Binder对象即可。这样就很大程度上简化了我们的工作。

IPC方式的优缺点和适用场景

名称 优点 缺点 场景 Bundle 简单易用 只能传输Bundle支持的数据类型 四大组件间的进程间通信 文件共享 简单易用 不适合高并发场景,并且无法做到进程间的即时通信 无并发访问情形,交换简单的数据是实时不高的场景 AIDL 功能强大,支持一对多并发通信,支持实时通信 使用稍复杂,需要处理好线程同步 一对多通信具有RPC需求 Messenger 功能一般,支持一对多串行通信,支持实时通信 不能很好的处理高并发情形,不支持RPC,数据通过Message进行传输,因此zhinengchuanshuBundle支持的数据类型 低并发的一对多即时通信,无RPC需求,或者无需要返回结果的RPC需求 ContentProvider 在数据源访问方面功能强大,支持一对多并发数据共享,可通过Call方法拓展其他操作 可以理解为受约束的AIDL,主要提供数据源的增删改查的操作 一对多的进程间的数据共享 Socket 功能强大,可以通过网络传输字节流,支持一对多并发实时通信 实现细节稍微繁琐,不支持直接的RPC 网络数据交换
0 0
原创粉丝点击