美文网首页
2.5 Binder连接池

2.5 Binder连接池

作者: 武安长空 | 来源:发表于2016-06-17 15:53 被阅读295次

    1. aidl实现流程概述

    首先建立一个aidl接口和一个Service,接着实现一个类A继承aidl接口中的Stub类并实现其中的方法,在Service绑定时返回类A的对象,然后客户端就可以绑定服务端,建立连接后就可以访问远程服务端的方法了。

    2. 可能出现的问题及解决方式

    公司项目越来越大,100个aidl,按照上面的思路,得100个Service。这显然不可以,解决方式是binder 连接池。
    整个工作机制是这样的:每个业务模块创建自己的aidl接口并实现此接口,这个时候不同业务模块之间是不能有耦合的,然后向服务端提供自己的唯一标识和其对应的Binder对象;对于服务端来说,只需要一个Service,服务端提供一个queryBinder接口,这个接口能够根据业务模块特征来返回相应的Binder对象给他们,不同的业务模块拿到所需的Binder对象后就可以进行远程方法调用了。
    Binder连接池的主要作用就是将每个业务模块的Binder请求同一转发到远程Service中去,避免重复创建Service的过程。

    3. 定义两个业务aidl接口并实现

    package qingfengmy.developmentofart._2activity.binderpool.aidl;
    
    interface ICompute {
        int add(int a, int b);
    }
    
    // ISecurityCenter.aidl
    package qingfengmy.developmentofart._2activity.binderpool.aidl;
    
    interface ISecurityCenter {
        String encrypt(in String content);
        String decrypt(in String password);
    }
    
    public class SecurityCenterImpl extends ISecurityCenter.Stub {
        @Override
        public String encrypt(String content) throws RemoteException {
            char[] chars = content.toCharArray();
            for (int i=0; i<chars.length;i++) {
                chars[i] = (char) (chars[i]+1);
            }
    
            return new String(chars);
        }
    
        @Override
        public String decrypt(String password) throws RemoteException {
            char[] chars = password.toCharArray();
            for (int i=0; i<chars.length;i++) {
                chars[i] = (char) (chars[i]-1);
            }
    
            return new String(chars);
        }
    }
    
    public class ComputerImpl extends ICompute.Stub {
        @Override
        public int add(int a, int b) throws RemoteException {
            return a+b;
        }
    }
    

    4. 定义BinderPool接口并实现

    package qingfengmy.developmentofart._2activity.binderpool.aidl;
    
    interface IBinderPool {
        IBinder queryBinder(int binderCode);
    }
    
    public static class BinderPoolImpl extends IBinderPool.Stub{
    
        @Override
        public IBinder queryBinder(int binderCode) throws RemoteException {
            switch (binderCode) {
                case 0:
                    return new SecurityCenterImpl();
                case 1:
                    return new ComputerImpl();
            }
            return null;
        }
    }
    

    5. 服务实现

    public class PoolService extends Service {
        private Binder mBinderPool = new BinderPool.BinderPoolImpl();
    
        public PoolService() {
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            return mBinderPool;
        }
    
    }
    

    6. BinderPool的实现

    public class BinderPool {
    
        // 定义BinderCode
        private 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;
        // volatile 用来修饰被不同线程访问和修改的变量
        private static volatile BinderPool sInstance;
        /**
         * CountDownLatch类是一个同步计数器,构造时传入int参数,该参数就是计数器的初始值,每调用一次countDown()方法,计数器减1,计数器大于0 时,await()方法会阻塞程序继续执行
         * CountDownLatch如其所写,是一个倒计数的锁存器,当计数减至0时触发特定的事件。利用这种特性,可以让主线程等待子线程的结束。
         */
        private CountDownLatch mConnectBinderPoolCountDownLatch;
    
        private BinderPool(Context context) {
            mContext = context.getApplicationContext();
            connectBinderPoolService();
        }
    
        public static BinderPool getsInstance(Context context) {
            if (sInstance == null) {
                synchronized (BinderPool.class) {
                    if (sInstance == null) {
                        sInstance = new BinderPool(context);
                    }
                }
            }
            return sInstance;
        }
    
        public IBinder queryBinder(int binderCode) {
            try {
                return mBinderPool.queryBinder(binderCode);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
            return null;
        }
    
        private synchronized void connectBinderPoolService() {
            // 只有一个线程有效
            mConnectBinderPoolCountDownLatch = new CountDownLatch(1);
            Intent intent = new Intent(mContext, PoolService.class);
            mContext.bindService(intent, mBinderPoolConnection, Context.BIND_AUTO_CREATE);
            // 等待,直到CountDownLatch中的线程数为0
            mConnectBinderPoolCountDownLatch.await();
        }
    
        private ServiceConnection mBinderPoolConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                mBinderPool = IBinderPool.Stub.asInterface(service);
                mBinderPool.asBinder().linkToDeath(mBinderPoolDeathRecipient, 0);
                // 执行一次countDown,其计数减一
                mConnectBinderPoolCountDownLatch.countDown();
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
    
            }
        };
    
        private IBinder.DeathRecipient mBinderPoolDeathRecipient = new IBinder.DeathRecipient() {
            @Override
            public void binderDied() {
                // 解除死亡绑定
                mBinderPool.asBinder().unlinkToDeath(mBinderPoolDeathRecipient, 0);
                mBinderPool = null;
                // 重连
                connectBinderPoolService();
            }
        };
    
        public static class BinderPoolImpl extends IBinderPool.Stub {
    
            @Override
            public IBinder queryBinder(int binderCode) throws RemoteException {
                switch (binderCode) {
                    case BINDER_SECURITY_CENTER:
                        return new SecurityCenterImpl();
                    case BINDER_COMPUTE:
                        return new ComputerImpl();
                }
                return null;
            }
        }
    }
    

    7. Activity中调用

    private void doWork() {
        BinderPool binderPool = BinderPool.getsInstance(this);
        IBinder computeBinder = binderPool.queryBinder(BinderPool.BINDER_COMPUTE);
        ICompute compute = ComputerImpl.asInterface(computeBinder);
        try {
            int result = compute.add(1, 2);
            Log.e("aaa", "1+2=" + result);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    
        IBinder securityCenterBinder = binderPool.queryBinder(BinderPool.BINDER_SECURITY_CENTER);
        ISecurityCenter iSecurityCenter = SecurityCenterImpl.asInterface(securityCenterBinder);
        try {
            String content = "i love this book";
            Log.e("aaa","加密前:"+content);
            content = iSecurityCenter.encrypt(content);
            Log.e("aaa","加密后:"+content);
            content = iSecurityCenter.decrypt(content);
            Log.e("aaa","解密后:"+content);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    
    }
    

    普通写法

    public void onServiceConnected(ComponentName name, IBinder service) {
        iBookManager = IBookManager.Stub.asInterface(service);
    }
    

    可见使用BinderPool客户端中的处理还是一样,通过Stub的asInterface方法把IBinder转为业务接口。
    这样有新业务aidl时,只需加aidl_code,并在queryBinder中增加返回的aidl即可。不需写Servicce,所以如果使用aidl,必须推荐使用BinderPool模式。

    相关文章

      网友评论

          本文标题:2.5 Binder连接池

          本文链接:https://www.haomeiwen.com/subject/jfevdttx.html