当很多模块都需要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的CountDownLatch,并让所有线程都在这个锁上等待,那么我们可以很轻松地完成测试。我们只需调用 一次countDown()方法就可以让所有的等待线程同时恢复执行。
- 开始执行前等待n个线程完成各自任务:例如应用程序启动类要确保在处理用户请求前,所有N个外部系统已经启动和运行了。
- 死锁检测:一个非常方便的使用场景是,你可以使用n个线程访问共享资源,在每次测试阶段的线程数目是不同的,并尝试产生死锁。
总结
这样以来我们就能在我们的应用中只建立一个Service就足够了。当我们添加一个AIDL接口的时候只需要在BinderPool中添加一个id,然后根据这个id,在BinderPoolImpl中创建一个对应的Binder对象即可。这样就很大程度上简化了我们的工作。
IPC方式的优缺点和适用场景
名称 | 优点 | 缺点 | 场景 |
---|---|---|---|
Bundle | 简单易用 | 只能传输Bundle支持的数据类型 | 四大组件间的进程间通信 |
文件共享 | 简单易用 | 不适合高并发场景,并且无法做到进程间的即时通信 | 无并发访问情形,交换简单的数据是实时不高的场景 |
AIDL | 功能强大,支持一对多并发通信,支持实时通信 | 使用稍复杂,需要处理好线程同步 | 一对多通信具有RPC需求 |
Messenger | 功能一般,支持一对多串行通信,支持实时通信 | 不能很好的处理高并发情形,不支持RPC,数据通过Message进行传输,因此zhinengchuanshuBundle支持的数据类型 | 低并发的一对多即时通信,无RPC需求,或者无需要返回结果的RPC需求 |
ContentProvider | 在数据源访问方面功能强大,支持一对多并发数据共享,可通过Call方法拓展其他操作 | 可以理解为受约束的AIDL,主要提供数据源的增删改查的操作 | 一对多的进程间的数据共享 |
Socket | 功能强大,可以通过网络传输字节流,支持一对多并发实时通信 | 实现细节稍微繁琐,不支持直接的RPC | 网络数据交换 |