在上个小节中,我们学习了AIDL的基本用法,这里先来回顾一下大致流程:首先创建一个Service和一个AIDL接口,接着创建一个类继承自AIDL中的Sub类并实现Sub类中的抽象方法,在Service中的onBind方法中返回这个类的对象,然后客户端就可以绑定服务端Service,建立连接后就可以访问远程服务端的方法了。
如果我们的项目中只有一个业务模块需要用到AIDL进行跨进程通信的话,上述方式完全可以应对。但随着我们项目日益庞大,现在有多个业务模块需要进行跨进程通信,该怎么解决呢?当然按照上述方式对每个模块一个一个按部就班也是可以的,不过这样子的话,我们的项目中就会存在多个进程,这显然不是最优的解决方式。我们可不可以只创建一个远程服务端进程来管理多个AIDL呢?答案是可以的,下面我们就一起来学习下Binder连接池。
为了说明问题,在这里我们提供两个AIDL接口(IDataOne 和 IDataTwo)用来模拟两个业务模块,分别用来处理 数据加减运算和数据乘除运算。声明如下:
// IDataOne.aidl
package com.example.administrator.binderpooltest;
interface IDataOne {
int add(int a, int b);
int minus(int a, int b);
}
// IDataTwo.aidl
package com.example.administrator.binderpooltest;
interface IDataTwo {
int multiply(int a, int b);
int divide(int a, int b);
}
上面两个AIDL接口实现代码如下:
package com.example.administrator.binderpooltest;
import android.os.RemoteException;
public class DataOneImpl extends IDataOne.Stub{
@Override
public int add(int a, int b) throws RemoteException {
return a + b;
}
@Override
public int minus(int a, int b) throws RemoteException {
return a - b;
}
}
package com.example.administrator.binderpooltest;
import android.os.RemoteException;
public class DataTwoImpl extends IDataTwo.Stub{
@Override
public int multiply(int a, int b) throws RemoteException {
return a * b;
}
@Override
public int divide(int a, int b) throws RemoteException {
return a / b; // 暂不考虑b为0的情况
}
}
现在业务模块的AIDL接口定义和实现都已经完成了,接下来我们来看下服务端和Binder连接池的代码实现:
首先为Binder连接池创建AIDL接口IBinderPool :
// IBinderPool.aidl
package com.example.administrator.binderpooltest;
interface IBinderPool {
IBinder queryBinder(int binderCode);
}
接着为Binder连接池创建远程Service并实现IBinderPool ,代码如下:
package com.example.administrator.binderpooltest;
public class Contat {
public static final int BINDER_DATA_ONE = 1;
public static final int BINDER_DATA_TWO = 2;
}
package com.example.administrator.binderpooltest;
import android.os.IBinder;
import android.os.RemoteException;
public class BinderPoolImpl extends IBinderPool.Stub{
@Override
public IBinder queryBinder(int binderCode) throws RemoteException {
IBinder binder = null;
switch (binderCode){
case Contat.BINDER_DATA_ONE:
binder = new DataOneImpl();
break;
case Contat.BINDER_DATA_TWO:
binder = new DataTwoImpl();
break;
default:
break;
}
return binder;
}
}
package com.example.administrator.binderpooltest;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.support.annotation.Nullable;
public class BinderPoolService extends Service{
private Binder mBinderPool = new BinderPoolImpl();
@Override
public void onCreate() {
super.onCreate();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinderPool;
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
记得Service需要在manifest文件中声明:
接下来看下Binder连接池的具体实现:
package com.example.administrator.binderpooltest;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import java.util.concurrent.CountDownLatch;
public class BinderPool {
private static final String TAG = "BinderPool";
private Context mContext;
private IBinderPool mBinderPool;
private static volatile BinderPool mInstance;
private CountDownLatch mCountDownLatch;
private BinderPool(Context context){
mContext = context.getApplicationContext();
connectBinderPoolService();
}
public static BinderPool getmInstance(Context context){
if (mInstance == null){
synchronized (BinderPool.class){
if (mInstance == null){
mInstance = new BinderPool(context);
}
}
}
return mInstance;
}
private synchronized void connectBinderPoolService(){
mCountDownLatch = new CountDownLatch(1);
Intent intent = new Intent(mContext,BinderPoolService.class);
mContext.bindService(intent,mBinderPoolConnection,Context.BIND_AUTO_CREATE);
try {
mCountDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
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() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mBinderPool = IBinderPool.Stub.asInterface(service);
try {
mBinderPool.asBinder().linkToDeath(mBinderPoolDeathRecipient,0);
}catch (RemoteException e){
e.printStackTrace();
}
mCountDownLatch.countDown();
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
private IBinder.DeathRecipient mBinderPoolDeathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
if (mBinderPool != null){
mBinderPool.asBinder().unlinkToDeath(mBinderPoolDeathRecipient,0);
}
mBinderPool = null;
connectBinderPoolService();
}
};
}
下面我们在客户端来验证一下,客户端代码编写如下:
package com.example.administrator.binderpooltest;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private Button mDataOneTest;
private Button mDataTwoTest;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initListener();
}
private void initView(){
mDataOneTest = (Button) findViewById(R.id.mDataOneTest);
mDataTwoTest = (Button) findViewById(R.id.mDataTwoTest);
}
private void initListener(){
mDataOneTest.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
BinderPool binderPool = BinderPool.getmInstance(MainActivity.this);
IBinder dataOneBinder = binderPool.queryBinder(Contat.BINDER_DATA_ONE);
IDataOne mDataOne = IDataOne.Stub.asInterface(dataOneBinder);
try {
int addResult = mDataOne.add(2,3);
Log.e(TAG,"result 2 + 3 = "+addResult);
int minusResult = mDataOne.minus(8,2);
Log.e(TAG,"result 8 - 2 = "+minusResult);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}).start();
}
});
mDataTwoTest.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
BinderPool binderPool = BinderPool.getmInstance(MainActivity.this);
IBinder dataTwoBinder = binderPool.queryBinder(Contat.BINDER_DATA_TWO);
IDataTwo mDataTwo = IDataTwo.Stub.asInterface(dataTwoBinder);
try {
int multiplyResult = mDataTwo.multiply(2,3);
Log.e(TAG,"result 2 * 3 = "+multiplyResult);
int divideResult = mDataTwo.divide(8,2);
Log.e(TAG,"result 8 / 2 = "+divideResult);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}).start();
}
});
}
}
分别点击按钮,测试结果如下:
09-02 00:18:32.185 17275-18727/com.example.administrator.binderpooltest E/MainActivity: result 2 + 3 = 5
09-02 00:18:32.185 17275-18727/com.example.administrator.binderpooltest E/MainActivity: result 8 - 2 = 6
09-02 00:18:33.845 17275-18754/com.example.administrator.binderpooltest E/MainActivity: result 2 * 3 = 6
09-02 00:18:33.845 17275-18754/com.example.administrator.binderpooltest E/MainActivity: result 8 / 2 = 4
可以看到程序正常运行。由此可见,Binder连接池能够极大提高AIDL的开发效率,并且可以避免大量的Service创建,建议我们在AIDL开发工作中引入BinderPool机制。