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模式。
网友评论