在 Android 多进程通信中,我们使用最多的就是 AIDL。前面我们已经说过了 AIDL 的具体使用方法,客户端连接服务端的 Service,然后通过服务端返回的 Binder 再结合 AIDL 类型接口即可让客户端调用到服务端中的方法并与之进行通信,使用起来很简单。试想一下,如果服务端定义了多个 AIDL 接口,一个 AIDL 接口绑定一个 Service,那岂不是在服务端要开启多个后台 Service,10 个还能接受,100个呢?1000个呢?所以显然这样是不可行的。
而我们的解决方案就是通过定义一个 IBinderPool 这样的 AIDL 接口对服务端所有的 AIDL 接口进行管理,然后服务端只需要创建一个与 IBinderPool 绑定的 Service,客户端就像可以通过绑定这一个 Service 即可获取想要的 AIDL 类型接口然后进行相应的方法调用。思想很简单,就类似买房和卖房一样,比如桂芳园小区的每一户房屋就相当于服务端的多个 AIDL 接口,小区旁边的链家房产中介就相当于服务端的 IBinderPool 接口,卖房的人把房产信息挂到链家中介,而我们想买房的人只需要找链家中介即可。也就是客户端获取到 IBinderPool 就可以调用我们想调用的 AIDL 接口。下面看一下具体实现:
ICalculate1.aidl:
// ICalculate1.aidl
package com.cfm.binderpooltest;
interface ICalculate1 {
// 提供加减法的计算器 1
int add(int a, int b);
int subtraction(int a, int b);
}
ICalculate2.aidl:
// ICalculate2.aidl
package com.cfm.binderpooltest;
interface ICalculate2 {
// 提供乘除法的计算器 2
int multip(int a, int b);
int division(int a, int b);
}
IBinderPool.aidl:
// IBinderPool.aidl
package com.cfm.binderpooltest;
interface IBinderPool {
IBinder queryBinder(int binderCode);
}
Calculate1Impl.java:
package com.cfm.binderpooltest;
/**
* 第一个 AIDL 接口的具体实现类
*/
public class Calculate1Impl extends ICalculate1.Stub {
private static final String TAG = "cfmtest";
@Override
public int add(int a, int b) throws RemoteException {
Log.d(TAG, "服务端开始计算加法");
return (a+b);
}
@Override
public int subtraction(int a, int b) throws RemoteException {
Log.d(TAG, "服务端开始计算减法");
return (a-b);
}
}
Calculate2Impl.java:
package com.cfm.binderpooltest;
/**
* 第二个 AIDL 接口的具体实现类
*/
public class Calculate2Impl extends ICalculate2.Stub {
private static final String TAG = "cfmtest";
@Override
public int multip(int a, int b) throws RemoteException {
Log.d(TAG, "服务端开始计算乘法");
return (a*b);
}
@Override
public int division(int a, int b) throws RemoteException {
Log.d(TAG, "服务端开始计算除法");
return (a/b);
}
}
BinderPoolService.java:(服务端)
package com.cfm.binderpooltest;
public class BinderPoolService extends Service {
private static final String TAG = "cfmtest";
private static final int BINDER_CALCULATE_1 = 1;
private static final int BINDER_CALCULATE_2 = 2;
private IBinder mBinderPool;
public BinderPoolService() {
}
@Override
public void onCreate() {
Log.d(TAG, "客户端绑定服务成功!");
super.onCreate();
mBinderPool = new BinderPoolImpl();
}
/**
* 客户端所获取到的 IBinder 接口,然后通过传入请求操作的 AIDL 接口对应的
* 标示符,获取到相应的 AIDL 接口类型实例。
*/
private class BinderPoolImpl extends IBinderPool.Stub {
@Override
public IBinder queryBinder(int binderCode) throws RemoteException {
IBinder binder = null;
switch (binderCode) {
case BINDER_CALCULATE_1:
binder = new Calculate1Impl();
break;
case BINDER_CALCULATE_2:
binder = new Calculate2Impl();
break;
default:
break;
}
return binder;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinderPool;
}
}
ClientActivity.java:(客户端)
package com.cfm.binderpooltest;
public class ClientActivity extends AppCompatActivity {
private static final String TAG = "cfmtest";
private static final int BINDER_CALCULATE_1 = 1;
private static final int BINDER_CALCULATE_2 = 2;
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// 客户端连接服务端后返回的 Binder 类型是 IBinderPool
IBinderPool binderPool = IBinderPool.Stub.asInterface(service);
// 然后我们再调用 IBinderPool 中的 queryBinder 方法获取我们想要使用的 AIDL 接口
try {
ICalculate1 iCalculate1 = ICalculate1.Stub.asInterface(binderPool.queryBinder(BINDER_CALCULATE_1));
ICalculate2 iCalculate2 = ICalculate2.Stub.asInterface(binderPool.queryBinder(BINDER_CALCULATE_2));
Log.d(TAG, "客户端计算 6 加 2 为: " + iCalculate1.add(6, 2) );
Log.d(TAG, "客户端计算 6 减 2 为: " + iCalculate1.subtraction(6, 2) );
Log.d(TAG, "客户端计算 6 乘 2 为: " + iCalculate2.multip(6, 2) );
Log.d(TAG, "客户端计算 6 除 2 为: " + iCalculate2.division(6, 2) );
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_client);
// 绑定服务端
Intent intent = new Intent(this, BinderPoolService.class);
bindService(intent, conn, Context.BIND_AUTO_CREATE);
}
}
AndroidManifest.xml:
...
<service
android:name=".BinderPoolService"
android:enabled="true"
android:exported="true"
android:process=".remote">
</service>
<activity android:name=".ClientActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
...
Log 打印信息:
服务端:
2019-05-27 21:33:06.790 15680-15680/.remote D/cfmtest: 客户端绑定服务成功!
2019-05-27 21:33:06.853 15680-15695/.remote D/cfmtest: 服务端开始计算加法
2019-05-27 21:33:06.854 15680-15695/.remote D/cfmtest: 服务端开始计算减法
2019-05-27 21:33:06.856 15680-15695/.remote D/cfmtest: 服务端开始计算乘法
2019-05-27 21:33:06.857 15680-15695/.remote D/cfmtest: 服务端开始计算除法
客户端:
2019-05-27 21:33:06.854 15661-15661/com.cfm.binderpooltest D/cfmtest: 客户端计算 6 加 2 为: 8
2019-05-27 21:33:06.855 15661-15661/com.cfm.binderpooltest D/cfmtest: 客户端计算 6 减 2 为: 4
2019-05-27 21:33:06.857 15661-15661/com.cfm.binderpooltest D/cfmtest: 客户端计算 6 乘 2 为: 12
2019-05-27 21:33:06.858 15661-15661/com.cfm.binderpooltest D/cfmtest: 客户端计算 6 除 2 为: 3