实现AIDL接口的Binder连接池
Binder作为AIDL通信的核心, 在使用中经常需要重复利用, 动态管理AIDL接口. Binder连接池的主要作用是把Binder请求统一发送至Service执行, 即动态管理Binder操作, 避免重复创建Service. 本文使用两种简单的AIDL服务, 使用Binder连接池动态切换, 含有演示Demo.
本文源码的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连接池相关推荐
- Android IPC机制(4)-Binder连接池
本系列的所有文章: Android IPC机制(1)-序列化机制 Android IPC机制(2)-AIDL Android IPC机制(3)-Messenger Android IPC机制(4)-B ...
- Binder Driver浅析:Binder线程池
线程池机制 大致流程 每个业务模块创建自己的AIDL接口并实现此接口,这个时候不同业务模块之间不能有耦合,所有实现细节单独开来,然后向服务端提供自己的唯一标识和其对应的Binder对象:对于服务端而言 ...
- java 实现 内存池_从连接池到内存池
注:内容微调,修改标题,让题文匹配. 如果将互联网应用比喻成冲浪的话, 可能需要先学会在"池"中游泳. 引子 AI赋能万物,老码农的伙伴们也曾经开发了一个基于图数据库的知识问答系统 ...
- day18 15.自定义连接池
我们写的是连接池吗?Connection对象绝对不能关.现在写的玩意不是连接池.因为现在讲的是JDBC,连接池也是JDBC里面的,人家那是SUN公司定义的标准.标准,你那不是标准.既然是标准,你做连接 ...
- JSP(Servlet)中从连接池获取连接
1) 建立连接. 2) 执行SQL. 3) 处理结果. 4) 释放资源. Connection pool:连接池 DataSource: LDAP ( Light directory access p ...
- mysql 存储引擎接口_MySQL 的基础一(连接池, SQL接口, 查询解析器, 查询优化器, 存储引擎接口, 执行器,)...
MySQL数据库的连接池 现在我们已经知道,我们任何一个系统都会有一个数据库连接池去访问数据库,也就是说这个系统会有多个数据库连接,供多线程并发的使用.同时我们可能会有多个系统同时去访问一个数据库,这 ...
- redis:redis介绍和安装、普通连接和连接池、redis 5大数据类型之字符串、Hash、列表、其他操作(通用)、管道、django使用redis、接口缓存
目录 一. redis介绍和安装 二. 普通连接和连接池 三. redis 5大数据类型之字符串 四. redis 5大数据类型之Hash 五. redis 5大数据类型之列表 六. 其他操作(通用) ...
- druid连接池参数配置不当引起接口耗时长
负责的消息中心推送服务出现接口耗时较长的现象,结合链路系统排查,发现在获取数据库连接这一步耗时很久 查看应用的数据库连接池监控,发现 连接池中的连接数变化频繁,有偶尔的等待连接的情况(与上述接口耗时慢 ...
- 连接池和协程池为何能提升并发能力?
你有没有发现,"内存池"和"进程池"都带有"池"字?其实,这两种技术都属于"池化技术".它通常是由系统预先分配一批资源并 ...
最新文章
- 使用Java辅助类(CountDownLatch、CyclicBarrier、Semaphore)并发编程
- “东湖”的艄公--漫步绍兴(四)
- hadoop博客 oschina
- 【LeetCode】两数之和
- mfc在运行的时候为什么没有实例化_为什么不建议把数据库部署在Docker容器内?...
- 前端学习(584):在dom中调试节点
- tga文件怎么打开_教你win10系统怎么打开stp文件
- Spring Boot项目CentOS域名的绑定
- mysql 删除表中 id不等于XXX的 并且XXX字段的重复记录
- LeetCode(226)——翻转二叉树(JavaScript)
- 三菱Q协议PLC TCP/IP通讯协议解析简述
- ffmpeg下载m3u8文件
- 省市区联动附(2020年省市区数据)
- 获取当前屏幕各种高度
- 小猫爪:i.MX RT1050学习笔记24-eDMA之eDMASAIASRC的“纠缠”(RT1170)
- 我的毕业设计历程——基于Unity3D的MOBA游戏设计(二)
- 计算机网络请子网划分,计算机网络不同主机数的子网划分
- USB Type A/B/C的区别和基本知识
- Uipath IIF判断使用
- 新手小白,做短视频自媒体创业,需要准备什么?