AIDL在Android开发过程中是一种非常常用的IPC方式,正常情况下我们每个AIDL服务都会对应一个service。假如我们有20个AIDL服务那岂不是要启动20个service?先不说20个服务对手机资源的占用,单单是代码管理就很凌乱。。。
有没有好的办法解决呢?当然有啦,这就是本文要介绍的内容——Binder连接池。Binder链接池本质上是通过一个AIDL管理其他AIDL,只需要一个service就能提供所有的AIDL服务。
先看看我写的demo,首先是demo的目录结构:
app是client端,ServiceDemo是服务端。
AIDl文件有三个:
IBinderPool
:Binder池,根据int值返回不同Binder
// IBinderPool.aidl
package com.servicedemo.server;
// Declare any non-default types here with import statements
interface IBinderPool {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
IBinder getBinder(int type);
}
IBinderA
:A服务
// IBinderA.aidl
package com.servicedemo.server;
// Declare any non-default types here with import statements
interface IBinderA {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void methodA(String paramA);
}
IBinderB
:B服务,代码和A类似,不再贴出来了,大家看demo就好了
BinderAImpl
和BinderBImpl
是IBinderA和IBinderB的实现,其中A的代码是:
public class BinderAImpl extends IBinderA.Stub{
@Override
public void methodA(String paramA) throws RemoteException {
Log.e("lzw","methodA");
}
}
BinderBImpl
和BinderAImpl
类似,代码参考demo。
下面看BinderPoolService
的实现:根据不同的type返回不同的Binder即可
public class BinderPoolService extends Service {
public BinderPoolService() {
}
@Override
public IBinder onBind(Intent intent) {
return new IBinderPool.Stub() {
@Override
public IBinder getBinder(int type) throws RemoteException {
// 根据不同的type返回BinderAImpl或者BinderBImpl
switch (type) {
case 1:
return new BinderAImpl();
default:
return new BinderBImpl();
}
}
};
}
}
看一下client如何调用:
1. 首先封装一个工具类BinderPoolTool
:
public class BinderPoolTool {
private Context c;
private static BinderPoolTool INSTANCE;
private IBinderPool pool;
private ServiceConnection mBinderConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.e("lzw","onServiceConnected");
pool = IBinderPool.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.e("lzw","onServiceDisconnected");
}
};
private BinderPoolTool(Context c){
this.c = c.getApplicationContext();
bindAidl();
}
public static BinderPoolTool getInstance(Context c){
if(INSTANCE == null){
synchronized (ServiceConnection.class){
if(INSTANCE == null){
INSTANCE = new BinderPoolTool(c);
}
}
}
return INSTANCE;
}
// 绑定BinderPool服务
private void bindAidl(){
Intent i = new Intent("com.binderpool");
i.setPackage("com.servicedemo.server");
c.bindService(i,mBinderConnection,Context.BIND_AUTO_CREATE);
}
// 对外暴露的获取Binder的方法,调用BinderPool服务的getBinder方法返回Binder
public IBinder getBinder(int type){
IBinder binder = null;
try {
binder = pool.getBinder(type);
} catch (RemoteException e) {
e.printStackTrace();
}
return binder;
}
}
代码很简洁,工具类是一个单例,在构造函数中绑定BinderPool服务拿到BinderPool的实例。getBinder
方法是对外暴露的,内部实现是调用了BinderPool的实例调用它的getBinder
去获取不同的Binder。
下面看一下client的调用:
public class MainActivity extends AppCompatActivity {
private BinderPoolTool pool;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 拿到BinderPoolTool的实例
pool = BinderPoolTool.getInstance(this);
}
public void onClick(View v){
switch (v.getId()){
case R.id.btn3:
// 这里一定要用IBinderA.Stub.asInterface转换pool.getBinder拿到的Binder
// 不能直接进行类型强制转换
IBinderA a = IBinderA.Stub.asInterface(pool.getBinder(1));
try {
a.methodA("");
} catch (RemoteException e) {
e.printStackTrace();
}
break;
case R.id.btn4:
IBinderB b = IBinderB.Stub.asInterface(pool.getBinder(0));
try {
b.methodB("");
} catch (RemoteException e) {
e.printStackTrace();
}
break;
}
}
}
很简单,拿到工具类的实例后,通过getBinder
方法获取到对应的实例,在调用对应Binder的方法即可。