个人博客
http://www.milovetingting.cn
使用BinderPool管理AIDL
前言
平时我们用到AIDL
,一般的流程可能是这样:
如果我们只是用到比较少的AIDL调用,那么上面的方法的确是可行的,但是,如果需要调用数量较多的AIDL,那么可以通过先访问一个BinderPool,然后再由BinderPool来查询相关的Binder服务,再将Binder服务返回。通过这种统一管理的方式,可以方便地管理AIDL。
下面详细介绍BinderPool具体的定义
定义IBinderPool
定义IBinderPool
,queryBinder
方法返回IBinder
对象
1 2 3
| interface IBinderPool { IBinder queryBinder(int queryCode); }
|
定义BinderPool
将BinderPool
定义为单例模式
。通过getInstance
获取到BinderPool的实例,并在构造方法
中连接BinderPoolService
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| private static class BinderPoolHolder { static final BinderPool INSTANCE = new BinderPool(); }
public static BinderPool getInstance(Context context) { mContext = context.getApplicationContext(); return BinderPoolHolder.INSTANCE; }
private BinderPool() { connectBinderPoolService(); }
private synchronized void connectBinderPoolService() { countDownLatch = new CountDownLatch(1); Intent intent = new Intent(mContext, BinderPoolService.class); mContext.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE); try { countDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } }
|
BinderPoolService
返回IBinderPool对象
1 2 3 4 5 6 7
| public class BinderPoolService extends Service { @Nullable @Override public IBinder onBind(Intent intent) { return new BinderPool.BinderPoolImpl(); } }
|
BinderPoolImpl
实现IBinderPool
接口方法,queryBinder根据queryCode返回对应的Binder
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| static class BinderPoolImpl extends IBinderPool.Stub {
@Override public IBinder queryBinder(int queryCode) throws RemoteException { IBinder binder = null; switch (queryCode) { case QUERY_CODE_BINDER_A: binder = new BinderA(); break; case QUERY_CODE_BINDER_B: binder = new BinderB(); break; default: break; } return binder; } }
|
ServiceConnection
在onServiceConnected
返回Binder对象,并绑定DeathRecipient
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| private ServiceConnection serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { binderPool = IBinderPool.Stub.asInterface(service); try { binderPool.asBinder().linkToDeath(deathRecipient, 0); } catch (RemoteException e) { e.printStackTrace(); } countDownLatch.countDown(); }
@Override public void onServiceDisconnected(ComponentName name) {
} };
|
DeathRecipient
1 2 3 4 5 6 7 8
| private IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient() { @Override public void binderDied() { binderPool.asBinder().unlinkToDeath(deathRecipient, 0); binderPool = null; connectBinderPoolService(); } };
|
完整的BinderPool代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
| public class BinderPool {
public static final int QUERY_CODE_BINDER_A = 1;
public static final int QUERY_CODE_BINDER_B = 2;
private static Context mContext;
private CountDownLatch countDownLatch;
private IBinderPool binderPool;
public static BinderPool getInstance(Context context) { mContext = context.getApplicationContext(); return BinderPoolHolder.INSTANCE; }
private BinderPool() { connectBinderPoolService(); }
private synchronized void connectBinderPoolService() { countDownLatch = new CountDownLatch(1); Intent intent = new Intent(mContext, BinderPoolService.class); mContext.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE); try { countDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } }
public IBinder queryBinder(int queryCode) { IBinder binder = null; if (binderPool != null) { try { binder = binderPool.queryBinder(queryCode); } catch (RemoteException e) { e.printStackTrace(); } } return binder; }
private static class BinderPoolHolder { static final BinderPool INSTANCE = new BinderPool(); }
private ServiceConnection serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { binderPool = IBinderPool.Stub.asInterface(service); try { binderPool.asBinder().linkToDeath(deathRecipient, 0); } catch (RemoteException e) { e.printStackTrace(); } countDownLatch.countDown(); }
@Override public void onServiceDisconnected(ComponentName name) {
} };
private IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient() { @Override public void binderDied() { binderPool.asBinder().unlinkToDeath(deathRecipient, 0); binderPool = null; connectBinderPoolService(); } };
static class BinderPoolImpl extends IBinderPool.Stub {
@Override public IBinder queryBinder(int queryCode) throws RemoteException { IBinder binder = null; switch (queryCode) { case QUERY_CODE_BINDER_A: binder = new BinderA(); break; case QUERY_CODE_BINDER_B: binder = new BinderB(); break; default: break; } return binder; } } }
|
定义IBinderA及实现类
1 2 3
| interface IBinderA { int calc(int a,int b); }
|
1 2 3 4 5 6
| public class BinderA extends IBinderA.Stub { @Override public int calc(int a, int b) throws RemoteException { return a + b; } }
|
定义IBinderB及实现类
1 2 3
| interface IBinderB { String getInfo(String info); }
|
1 2 3 4 5 6
| public class BinderB extends IBinderB.Stub { @Override public String getInfo(String info) throws RemoteException { return info + "-handled"; } }
|
客户端调用BinderPool
由于在连接BinderPoolService时,是通过调用CountDownLatch.await(),等待onServiceConnected的回调,因此如果直接在主线程调用BinderPool的方法,会导致主线程阻塞,发生ANR,因此需要放到子线程去处理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| new Thread(new Runnable() { @Override public void run() { try { IBinder binder = BinderPool.getInstance(getApplicationContext()).queryBinder(BinderPool.QUERY_CODE_BINDER_A); final int calc = IBinderA.Stub.asInterface(binder).calc(1, 2); runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(getApplicationContext(), "calc:" + calc, Toast.LENGTH_SHORT).show(); } }); IBinder binderB = BinderPool.getInstance(getApplicationContext()).queryBinder(BinderPool.QUERY_CODE_BINDER_B); final String info = IBinderB.Stub.asInterface(binderB).getInfo("hello"); runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(getApplicationContext(), "info:" + info, Toast.LENGTH_SHORT).show(); } }); } catch (RemoteException e) { e.printStackTrace(); } } }).start();
|
总结
通过定义BinderPool来管理所有的AIDL连接,当需要新增AIDL时,只需要增加对应的AIDL接口及对应的实现Binder,然后在BinderPool的queryBinder增加对应的queryCode处理即可。