1. 最常用的进程间通信方式
- AIDL 是最常用的 IPC 方式,是日常开发中涉及进程间通信时的首选
2. 典型的 AIDL 的使用流程
- 创建一个 Service 和一个 AIDL 接口
- 创建一个类继承 AIDL 接口中的 Stub 类并实现 Stub 中的抽象方法,在 Service 的
onBind()
方法中返回这个类的对象 - 客户端绑定服务端 Service,建立连接后即可访问远程服务端方法
3. 多个业务模块都需要使用 AIDL 的场景下的工作机制
客户端
- 每个业务模块创建自己的 AIDL 接口并实现此接口
- 此时不同业务模块之间不能耦合,所有实现细节要单独开来
- 向服务端提供自己的唯一标识和其对应的 Binder 对象
服务端
- 只需要一个 Service 即可,服务端提供一个 queryBinder 接口
- 这个接口能够根据业务模块的特征来返回相应的 Binder 对象给它们
- 不同的业务模块拿到所需的 Binder 对象后就可以进行远程方法调用
4. Binder 连接池的主要作用
- 将每个业务模块的 Binder 请求统一转发到远程 Service 中去执行
- 避免了重复创建 Service 的过程(Service 是四大组件之一,本身就是一种系统资源),可以极大提高 AIDL 的开发效率
5. Binder 连接池的工作原理
6. Binder 连接池的代码实现 Demo
提供两个 AIDL 接口,模拟多个业务模块都要使用 AIDL 的场景
1
2
3
4
5// ISecurityCenter 接口提供加解密功能
interface ISecurityCerter {
String encrypt(String content);
String decrypt(String password);
}1
2
3
4// ICompute 接口提供计算加法的功能
interface ICompute {
int add(int a, int b);
}上面两个业务模块 AIDL 接口的实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17public class SecurityCenterImpl extends ISecurityCenter.Stub {
private static final char SECRET_CODE = '^';
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);
}
public String decrypt(String password) throws RemoteException {
return encrypt(password);
}
}1
2
3
4
5
6public class ComputeImpl extends ICompute.Stub {
public int add() throws RemoteException {
return a + b;
}
}为 Binder 连接池创建 AIDL 接口
IBinderPool.aidl
1
2
3
4
5
6
7/**
* @Param binderCode, the unique token of specific Binder<br/>
* @return specific Binder who's token is binderCode.
*/
interface IBinderPool {
IBinder queryBinder(int binderCode);
}为 Binder 连接池创建远程 Service 并实现 IBinderPool
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20public class BinderPoolService extends Service {
private static final String TAG = "BinderPoolService";
private Binder mBinderPool = new BinderPool.BinderPoolImpl();
public void onCreate() {
super.onCreate();
}
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind");
return mBinderPool;
}
public void onDestroy() {
super.onDestroy();
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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;
}Binder 连接池的具体实现
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110public class BinderPool {
private static final String TAG = "BinderPool";
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();
}
// BinderPool 是一个单例实现,因此在同一个进程中只会初始化一次
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();
}
}
/**
* query binder by binderCode from binder pool
* @Param binderCode
* the unique token of binder
* @Param binder who's token is binderCode<br>
* return null when not found or BinderPoolService died.
*/
public IBinder queryBinder(int binderCode) {
IBinder binder = null;
try {
if (mBinderPool != null) {
binder = mBinderPool.queryBinder(binderCode);
}
} catch (RemoteException e) {
e.printStackTrace();
}
return binder;
}
private ServiceConnection mBinderPoolConnection = new ServiceConnection() {
public void onServiceDisconnected(ComponentName name) {
// ignored.
}
public void onServiceConnected(ComponentName name, IBinder service) {
mBinderPool = IBinderPool.Stub.asInterface(service);
try {
mBinderPool.asBinder().linkToDeath(mBinderPoolDeathRecipient, 0);
} catch (RemoteException e) {
e.printStackTrace();
}
// 通过 CountDownLatch 将 bindeService() 异步操作转换成同步操作
mConnectBinderPoolCountDownLatch.countDown();
}
};
// 断线重连
private IBInder.DeathRecipient mBinderPoolDeathRecipient = new IBinder.DeathRecipient() {
public void binderDied() {
Log.w(TAG, "binder died.");
mBinderPool.asBinder().unlinkToDeath(mBinderPoolDeathRecipient, 0);
mBinderPool = null;
connectBinderPoolService();
}
};
public static class BinderPoolImpl extends IBinderPool.Stub {
public BinderPoolImpl() {
super();
}
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;
}
}
}验证效果,新创建一个 Activity,在线程中执行如下操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23private void doWork() {
BinderPool binderPool = BinderPool.getInstance(BinderPoolActivity.this);
IBinder securityBinder = binderPool.queryBinder(BinderPool.BINDER_SECURITY_CENTER);
mSecurityCenter = (ISecurityCenter) SecurityCenterImpl.asInterface(securityBinder);
Log.d(TAG, "visit ISecurityCenter");
String msg = "Hello world-Android";
System.out.println("content:" + msg);
try {
String password = mSecurityCenter.encrypt(msg);
System.out.println("encrypt:" + password);
System.out.println("decrypt:" + mSecurityCenter.decrypt(password));
} catch (RemoteException e) {
e.printStackTrace();
}
Log.d(TAG, "visit ICompute");
IBinder computeBinder = binderPool.queryBinder(BinderPool.BINDER_COMPUTE);
try {
System.out.println("3+5=" + mCompute.add(3, 5));
} catch (RemoteException e) {
e.printStackTrace();
}
}