Binder作为AIDL通信的核心, 在使用中经常需要重复利用, 动态管理AIDL接口. Binder连接池的主要作用是把Binder请求统一发送至Service执行, 即动态管理Binder操作, 避免重复创建Service. 本文使用两种简单的AIDL服务, 使用Binder连接池动态切换, 含有演示Demo.

Binder

本文源码的GitHub下载地址


AIDL

模拟Binder连接池, 使用两个简单的AIDL接口与实现, 一个是加解密, 一个是加法.

加解密, AIDL提供两个方法, 即加密字符串和解密字符串.

package org.wangchenlong.binderpooldemo;interface ISecurityCenter {String encrypt(String content);String decrypt(String password);
}

加密和解密的实现, 使用简单的异或运算处理.

public class SecurityCenterImpl extends ISecurityCenter.Stub {private static final char SECRET_CODE = 'w';@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);}
}

AIDL的实现方法都需要设置RemoteException的异常抛出, 防止连接异常.

求和的AIDL接口

package org.wangchenlong.binderpooldemo;interface ICompute {int add(int a, int b);
}

求和的实现, 非常简单.

public class ComputeImpl extends ICompute.Stub {@Override public int add(int a, int b) throws RemoteException {return a + b;}
}

Binder连接池通过ID查找Bidner, 查询并返回匹配的Binder.

package org.wangchenlong.binderpooldemo;interface IBinderPool {IBinder queryBinder(int binderCode);
}

Binder 连接池

Service服务通过Binder连接池动态选择Binder请求.

private Binder mBinderPool = new BinderPool.BinderPoolImpl(); // 动态选择Binder@Nullable @Override public IBinder onBind(Intent intent) {Log.e(TAG, "onBind");return mBinderPool;
}

Binder连接池的具体实现, 创建BinderPool单例, 连接服务.

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

绑定服务, 通过CountDownLatch类, 把异步操作转换为同步操作, 防止绑定冲突.

private synchronized void connectBinderPoolService() {mCountDownLatch = new CountDownLatch(1); // 只保持一个绑定服务Intent service = new Intent(mContext, BinderPoolService.class);mContext.bindService(service, mBinderPoolConnection, Context.BIND_AUTO_CREATE);try {mCountDownLatch.await();} catch (InterruptedException e) {e.printStackTrace();}
}

通过DeathRecipient处理Binder连接池死亡重联机制.

// 失效重联机制, 当Binder死亡时, 重新连接
private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {@Override public void binderDied() {Log.e(TAG, "Binder失效");mBinderPool.asBinder().unlinkToDeath(mDeathRecipient, 0);mBinderPool = null;connectBinderPoolService();}
};// Binder的服务连接
private ServiceConnection mBinderPoolConnection = new ServiceConnection() {@Override public void onServiceConnected(ComponentName name, IBinder service) {mBinderPool = IBinderPool.Stub.asInterface(service);try {mBinderPool.asBinder().linkToDeath(mDeathRecipient, 0);} catch (RemoteException e) {e.printStackTrace();}mCountDownLatch.countDown();}@Override public void onServiceDisconnected(ComponentName name) {}
};

通过ID连接不同的Binder请求.

public IBinder queryBinder(int binderCode) {IBinder binder = null;try {if (mBinderPool != null) {binder = mBinderPool.queryBinder(binderCode);}} catch (RemoteException e) {e.printStackTrace();}return binder;
}

Binder连接池AIDL的具体实现, 通过ID选择Binder.

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_COMPUTE:binder = new ComputeImpl();break;case BINDER_SECURITY_CENTER:binder = new SecurityCenterImpl();break;default:break;}return binder;}
}

AIDL并不会直接生成, 使用AS的Build -> Make Project即可.


客户端

通过AIDL接口, 把耗时任务移到Service进行. 操作Binder需要在其他线程中执行, 使用Handler回调至主线程, 并更新页面.

public void encryptMsg(View view) {new Thread(new Runnable() {@Override public void run() {doEncrypt();}}).start();
}private void doEncrypt() {BinderPool binderPool = BinderPool.getInstance(getApplicationContext());IBinder securityBinder = binderPool.queryBinder(BinderPool.BINDER_SECURITY_CENTER);mISecurityCenter = SecurityCenterImpl.asInterface(securityBinder);String msg = "Hello, I am Spike!";try {String encryptMsg = mISecurityCenter.encrypt(msg);Log.e(TAG, "加密信息: " + encryptMsg);String decryptMsg = mISecurityCenter.decrypt(encryptMsg);Log.e(TAG, "解密信息: " + decryptMsg);Message hm = new Message();hm.what = 0;hm.obj = encryptMsg + "\n" + decryptMsg;mHandler.sendMessage(hm);} catch (RemoteException e) {e.printStackTrace();}
}

其他线程使用Handler向主线程传递数据, 在界面中显示效果.

加法操作类似.

public void addNumbers(View view) {new Thread(new Runnable() {@Override public void run() {doAddition();}}).start();
}private void doAddition() {BinderPool binderPool = BinderPool.getInstance(getApplicationContext());IBinder computeBinder = binderPool.queryBinder(BinderPool.BINDER_COMPUTE);mICompute = ComputeImpl.asInterface(computeBinder);try {int result = mICompute.add(12, 12);Log.e(TAG, "12 + 12 = " + result);Message hm = new Message();hm.what = 1;hm.obj = result + "";mHandler.sendMessage(hm);} catch (RemoteException e) {e.printStackTrace();}
}

注意AIDL需要捕获RemoteException的异常.


效果

效果

AIDL是较为高效的跨进程通信方式, 也是很多方式的低层实现; Binder连接池可以在同一服务中处理多个Binder请求, 节省资源, 因此需要熟练掌握.

OK, that's all! Enjoy it!

原文地址: http://www.jianshu.com/p/39c1c2bf39c6

实现AIDL接口的Binder连接池相关推荐

  1. Android IPC机制(4)-Binder连接池

    本系列的所有文章: Android IPC机制(1)-序列化机制 Android IPC机制(2)-AIDL Android IPC机制(3)-Messenger Android IPC机制(4)-B ...

  2. Binder Driver浅析:Binder线程池

    线程池机制 大致流程 每个业务模块创建自己的AIDL接口并实现此接口,这个时候不同业务模块之间不能有耦合,所有实现细节单独开来,然后向服务端提供自己的唯一标识和其对应的Binder对象:对于服务端而言 ...

  3. java 实现 内存池_从连接池到内存池

    注:内容微调,修改标题,让题文匹配. 如果将互联网应用比喻成冲浪的话, 可能需要先学会在"池"中游泳. 引子 AI赋能万物,老码农的伙伴们也曾经开发了一个基于图数据库的知识问答系统 ...

  4. day18 15.自定义连接池

    我们写的是连接池吗?Connection对象绝对不能关.现在写的玩意不是连接池.因为现在讲的是JDBC,连接池也是JDBC里面的,人家那是SUN公司定义的标准.标准,你那不是标准.既然是标准,你做连接 ...

  5. JSP(Servlet)中从连接池获取连接

    1) 建立连接. 2) 执行SQL. 3) 处理结果. 4) 释放资源. Connection pool:连接池 DataSource: LDAP ( Light directory access p ...

  6. mysql 存储引擎接口_MySQL 的基础一(连接池, SQL接口, 查询解析器, 查询优化器, 存储引擎接口, 执行器,)...

    MySQL数据库的连接池 现在我们已经知道,我们任何一个系统都会有一个数据库连接池去访问数据库,也就是说这个系统会有多个数据库连接,供多线程并发的使用.同时我们可能会有多个系统同时去访问一个数据库,这 ...

  7. redis:redis介绍和安装、普通连接和连接池、redis 5大数据类型之字符串、Hash、列表、其他操作(通用)、管道、django使用redis、接口缓存

    目录 一. redis介绍和安装 二. 普通连接和连接池 三. redis 5大数据类型之字符串 四. redis 5大数据类型之Hash 五. redis 5大数据类型之列表 六. 其他操作(通用) ...

  8. druid连接池参数配置不当引起接口耗时长

    负责的消息中心推送服务出现接口耗时较长的现象,结合链路系统排查,发现在获取数据库连接这一步耗时很久 查看应用的数据库连接池监控,发现 连接池中的连接数变化频繁,有偶尔的等待连接的情况(与上述接口耗时慢 ...

  9. 连接池和协程池为何能提升并发能力?

    你有没有发现,"内存池"和"进程池"都带有"池"字?其实,这两种技术都属于"池化技术".它通常是由系统预先分配一批资源并 ...

最新文章

  1. 使用Java辅助类(CountDownLatch、CyclicBarrier、Semaphore)并发编程
  2. “东湖”的艄公--漫步绍兴(四)
  3. hadoop博客 oschina
  4. 【LeetCode】两数之和
  5. mfc在运行的时候为什么没有实例化_为什么不建议把数据库部署在Docker容器内?...
  6. 前端学习(584):在dom中调试节点
  7. tga文件怎么打开_教你win10系统怎么打开stp文件
  8. Spring Boot项目CentOS域名的绑定
  9. mysql 删除表中 id不等于XXX的 并且XXX字段的重复记录
  10. LeetCode(226)——翻转二叉树(JavaScript)
  11. 三菱Q协议PLC TCP/IP通讯协议解析简述
  12. ffmpeg下载m3u8文件
  13. 省市区联动附(2020年省市区数据)
  14. 获取当前屏幕各种高度
  15. 小猫爪:i.MX RT1050学习笔记24-eDMA之eDMASAIASRC的“纠缠”(RT1170)
  16. 我的毕业设计历程——基于Unity3D的MOBA游戏设计(二)
  17. 计算机网络请子网划分,计算机网络不同主机数的子网划分
  18. USB Type A/B/C的区别和基本知识
  19. Uipath IIF判断使用
  20. 新手小白,做短视频自媒体创业,需要准备什么?

热门文章

  1. POJ 2420 A Star not a Tree?【爬山法】
  2. ZigZag Conversion leetcode java
  3. 从零开始编写自己的C#框架(17)——Web层后端首页
  4. 回溯算法超详细讲解(附代码)
  5. Golang 入门笔记(二)下
  6. 大数问题(一个特别大的数需要用数组或字符串来表示)
  7. oracle 一行转多行,oracle 一行变多行
  8. Matlab 实现对 Excel sheet 重命名 合并单元格
  9. [云炬创业管理笔记]第四章把握创业机会测试6
  10. [云炬创业基础笔记]第二章创业者测试20