IPC机制--BinderPool

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

首先,创建BinderPool的AIDL文件

// IBinderPool.aidl
package com.example.no_clay.messagertest.BinderPool;

// Declare any non-default types here with import statements

interface IBinderPool {
    IBinder queryBinder(int binderCode);
}

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

// ISecurityCenter.aidl
package com.example.no_clay.messagertest.BinderPool;

// Declare any non-default types here with import statements

interface ISecurityCenter {
    String encrypt(String content);
    String decrypt(String password);
}
// ICompute.aidl
package com.example.no_clay.messagertest.BinderPool;

// Declare any non-default types here with import statements

interface 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网络数据交换
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值