Android 进程间通信之 AIDL (二)高级用法及建议

本文介绍了如何利用 Binder 连接池优化 Android 多模块间的 AIDL 进程通信,避免创建过多 Service。通过创建 IBindlerPool 接口、实现连接池和服务端,简化了服务管理和客户端操作。在客户端操作时,需要注意在子线程中执行以防止阻塞主线程。使用 Binder 连接池可以提高开发效率,当新增业务模块时,只需在 BinderPoolImpl 中添加对应 Binder 即可。
  1. Bindler 连接池

          这里引用了任玉刚老师的<Android 开发艺术探索> 中的 Binder 连接池概念,本来想自己总结的,想了下其实任玉刚老师总结的挺好的就照搬过来了,一个字“懒”啊!偷笑。上一篇咱们介绍到了Android AIDL 基本用法还没有看过的同学可以先去温习下。

           现在假设有 N 个不同的业务模块需要使用 AIDL 来进行进程间通信,那我们该怎么处理勒?或许你会说“就按照  AIDL 的实现方式一个一个来实现吧”你有没有想过这样会创建 N 个 Service,当用户打开手机设置查看正在运行的进程,发现某某某 APP Service TMD 有10 个 甚至更多。他的第一反应也许是该卸载了,我们不可能无限制的创建 Service ,Service 是四大组件之一,是需要消耗内存的。而且太多的话会使我们的 APP 看起来特别很重量级。为了避免这种问题发生,咱们可以引用 Binder 连接池来解决这个问题,下面对 Bindler 连接池的代码实现做一下说明。首先,为了说明问题,我们提供了两个 AIDL 接口 ISecurityCenter 和 Icompute 来模拟上面提到的多模块应用的情况。

        一. 创建 ISecurityCenter ,Icompute 接口。

package android.t01.com.common;

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

interface ISecurityCenter {
    String encrypt(String content);
    String decrypt(String password);
}
package android.t01.com.common;

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

interface ICompute {
int add(int a, int b);
}

         二. 实现 AIDL 接口。

              为了便于理解这里简单处理

            

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);
    }

}




public class ComputeImpl extends ICompute.Stub {

    @Override
    public int add(int a, int b) throws RemoteException {
        return a + b;
    }

}

        三. 服务端和 Binder 连接池的准备工作。

             不知道有没有同学发现,咱们并没有为每个 Moudle AIDL 去单独创建 Service。

              1. 首先,创建 连接池接口 IBindlerPool.aidl。

                

interface IBinderPool {
    /**
     * @param binderCode, the unique token of specific Binder<br/>
     * @return specific Binder who's token is binderCode.
     */
    IBinder queryBinder(int binderCode);
}

                2. 实现 连接池接口

    

    public static class BinderPoolImpl extends IBinderPool.Stub {

        public BinderPoolImpl() {
            super();
        }

        @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;
        }
    }

                3. 创建服务端的 Servicer.

        

public class BinderPoolService extends Service {

    private static final String TAG = "BinderPoolService";

    private Binder mBinderPool = new BinderPool.BinderPoolImpl();

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "onBind");
        return mBinderPool;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

}

                     看起来是不是特简单大笑

                4. Bindler 连接池的具体实现。

public class BinderPool {
    private static final String TAG = "BinderPool";
    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 getInsance(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();
        }
    }


    /**
     * query binder by binderCode from binder pool
     *
     * @param binderCode
     *            the unique token of binder
     * @return binder who's token is binderCode<br>
     *         return null when not found or BinderPoolService died.
     */
    public IBinder queryBinder(int binderCode) {
        IBinder binder = null;
        try {
            if (mBinderPool != null) {
                binder = mBinderPool.queryBinder(binderCode);
            }
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        return binder;
    }

    private ServiceConnection mBinderPoolConnection = new ServiceConnection() {

        @Override
        public void onServiceDisconnected(ComponentName name) {
            // ignored.
        }

        @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() {
        @Override
        public void binderDied() {
            Log.w(TAG, "binder died.");
            mBinderPool.asBinder().unlinkToDeath(mBinderPoolDeathRecipient, 0);
            mBinderPool = null;
            connectBinderPoolService();
        }
    };


    public static class BinderPoolImpl extends IBinderPool.Stub {

        public BinderPoolImpl() {
            super();
        }

        @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;
        }
    }
}
  • Bindler  连接池的具体实现分析就完了,它的好处是显然易见的。

                5. 客服端操作。

   

private void doWork() {
        BinderPool binderPool = BinderPool.getInsance(MyBookActivity.this);
        IBinder securityBinder = binderPool
                .queryBinder(BinderPool.BINDER_SECURITY_CENTER);
        ;
        mSecurityCenter = (ISecurityCenter) SecurityCenterImpl
                .asInterface(securityBinder);
        Log.d(TAG, "visit ISecurityCenter");
        String msg = "helloworld-安卓";
        System.out.println("content:" + msg);
        try {
            String password = mSecurityCenter.encrypt(msg);
            System.out.println("encrypt:" + password);
            System.out.println("decrypt:" + mSecurityCenter.decrypt(password));
        } catch (RemoteException e) {
            e.printStackTrace();
        }

        Log.d(TAG, "visit ICompute");
        IBinder computeBinder = binderPool
                .queryBinder(BinderPool.BINDER_COMPUTE);
        ;
        ICompute mCompute = ComputeImpl.asInterface(computeBinder);
        try {
            System.out.println("3+5=" + mCompute.add(3, 5));
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
            

        注意:这里需要额外的说明下,为什么需要在子线程中去执行了?这是因为在 Bindler 连接池的实现中,我们需要通过 CountDownLatch 将 bindService 这一异步操作转换为同步操作,这就意味着他是需要耗时的并且 Bindler 中的方法调用也是耗时的,因此不建议放在主线程。


    总结

        有了 BinderPool 可以大大方便和提高日常的开发工作,比如如果有一个新的业务模块 B 需要添加新的 AIDL,那么在它实现了自己的 AIDL 接口后,只需要修改 BinderPoolImpl 中的 queryBinder 方法,给自己新添加一个 binderCode 并返回对应的 Binder 对象即可!


    建议

    
名称优点缺点适用场景
 Bundle简单易用只能传输 Bundle 支持的数据类型   四大组件的进程间
文件共享简单易用不适合高并发场景,并且无法做到进程间的即时通信无并发访问情形,交换简单的数据实时性不高的场景
AIDL功能强大,支持一对多并发,支持实时通信

使用稍复杂,需要处理好线程同步

一对多通信且有 RPC 需求
Messenger功能一般,支持一对多串行通信,支持实时通信不能很好处理高并发,只能传输 Bundle 数据低并发一对多
ContentProvider在数据源访问方面功能强大,支持一对多并发数据共享,可通过 Call 方法扩展其它操作可以理解为受约束的 AIDL一对多的进程间的数据共享
Socket功能强大,可以通过网络传输字节流,支持一对多并发实时通信实现细节稍微有点烦琐,不支持直接的 RPC网络数据交换

   

Demo 地址



评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值