个人博客

http://www.milovetingting.cn

使用BinderPool管理AIDL

前言

平时我们用到AIDL,一般的流程可能是这样:

  • 定义AIDL接口

  • 定义服务,在onBind方法中返回实现了AIDL接口的Stub类的实例

  • 调用bindService方法,在ServiceConnectiononServiceConnected回调中获取到Binder对象

  • 通过Binder对象调用接口中的方法

如果我们只是用到比较少的AIDL调用,那么上面的方法的确是可行的,但是,如果需要调用数量较多的AIDL,那么可以通过先访问一个BinderPool,然后再由BinderPool来查询相关的Binder服务,再将Binder服务返回。通过这种统一管理的方式,可以方便地管理AIDL。

下面详细介绍BinderPool具体的定义

定义IBinderPool

定义IBinderPoolqueryBinder方法返回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;
}
}

ServiceConnectiononServiceConnected返回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处理即可。