0
点赞
收藏
分享

微信扫一扫

【IPC实战④】Binder连接池


前言

在​​前面关于AIDL的讲解​​中,基本是一个AIDL对应一个Service。具体实现是把AIDL的实现类放到Sevice里面了,如图

【IPC实战④】Binder连接池_ide


所以就会有很大的局限性,即一个Service只能对应一个AIDL,假如说有多个模块,每个模块都有AIDL需求,那么就需要写多个Service,很显然这是很笨的写法,而Binder连接池就可以比较优雅的实现一个Service对应多个AIDL的需求

1.总体思路介绍

首先要把Stub的实现类和Service抽离,不让Service和他们有直接关系。再就是在Service的onBind方法中返回Binder连接池。这样用户再从连接池中取出相应的IBinder再去操作。

2.具体实现

①创建两个AIDL文件,模拟多个模块使用AIDL的情况

// ICalculate.aidl

interface ICalculate {
int add(in int num1,in int num2);
}

// ISpeak.aidl

interface ISpeak {
void speak();
}

②创建他们的实现类(不在Service里面)

其实这个实现类还是运行在服务端的进程中

/**
* Created by didiwei on 2022/5/21
* desc: ISpeak.aidl的实现类,这个类之前是放在Service中的,但是因为引入了Binder连接池,所以要把它和Service分开
* 但其实这个实现类还是运行在服务端的进程中
*/
public class SpeakImpl extends ISpeak.Stub{
@Override
public void speak() throws RemoteException {
int pid = android.os.Process.myPid();

Log.v("ljh","这里是SpeakImpl里的speak方法,当前进程ID为:" + pid);
}
}

/**
* Created by didiwei on 2022/5/21
* desc: ICalculate.aidl的实现类,这个类之前是放在Service中的,但是因为引入了Binder连接池,所以要把它和Service分开
* 但其实这个实现类还是运行在服务端的进程中
*/
public class CalculateImpl extends ICalculate.Stub {
@Override
public int add(int num1, int num2) throws RemoteException {
int pid = android.os.Process.myPid();

Log.v("ljh","这里是CalculateImpl里的add方法,当前进程ID为:" + pid);

return num1 + num2;
}
}

③创建Binder连接池的AIDL接口

// IBinderPool.aidl

interface IBinderPool {
IBinder queryBinder(in int binderCode);
}

④创建BinderPool类,在里面实现IBinderPool

/**
* Created by didiwei on 2022/5/21
* desc: 里面有IBinderPool的实现类
*/
public class BinderPool {
public static final int BINDER_SPEAK = 0;
public static final int BINDER_CALCULATE = 1;

private Context mContext;
private IBinderPool mBinderPool;
private static volatile BinderPool mInstance;//单例
private CountDownLatch mCountDownLatch;//实现线程同步的

//连接Service的回调
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mBinderPool = IBinderPool.Stub.asInterface(service);

try {
mBinderPool.asBinder().linkToDeath(mDeathRecipient,0);
} catch (RemoteException e) {
e.printStackTrace();
}

mCountDownLatch.countDown();
}

@Override
public void onServiceDisconnected(ComponentName name) {

}
};
//实现Service的重连
private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
mBinderPool.asBinder().unlinkToDeath(mDeathRecipient,0);
mBinderPool = null;

connectBinderPoolService();
}
};

private BinderPool(Context context){
this.mContext = context;

connectBinderPoolService();
}

public static BinderPool getInstance(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);

//连接Service
Intent service = new Intent(mContext,BinderPoolService.class);
mContext.bindService(service,mServiceConnection,Context.BIND_AUTO_CREATE);

try {
mCountDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

//对外暴露的 queryBinder 方法
public IBinder queryBinder(int binderCode){
IBinder iBinder = null;

if(mBinderPool != null){
try {
iBinder = mBinderPool.queryBinder(binderCode);
} catch (RemoteException e) {
e.printStackTrace();
}
}

return iBinder;
}

//IBinderPool的实现类
public static class BinderPoolImpl extends IBinderPool.Stub{

@Override
public IBinder queryBinder(int binderCode) throws RemoteException {
IBinder iBinder = null;
switch (binderCode){
case BINDER_SPEAK:
iBinder = new SpeakImpl().asBinder();
break;
case BINDER_CALCULATE:
iBinder = new CalculateImpl().asBinder();
break;
default:
break;
}
return iBinder;
}
}
}

⑤创建BinderPoolService

/**
* Created by didiwei on 2022/5/21
* desc: 服务端,这个Service只需要返回BinderPool即可
*/
public class BinderPoolService extends Service {
private int pid = android.os.Process.myPid();
private Binder mBinderPool = new BinderPool.BinderPoolImpl();//注意这里用Binder接收

public BinderPoolService() {
}

@Override
public IBinder onBind(Intent intent) {
Log.v("ljh","这里是Service里的onBind方法,当前进程ID为:" + pid);
return mBinderPool;
}
}

注意为Service另起进程

【IPC实战④】Binder连接池_ide_02

⑥客户端调用

public class MainActivity extends AppCompatActivity {
private ISpeak iSpeak;
private ICalculate iCalculate;
private int pid = android.os.Process.myPid();

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

new Thread(new Runnable() {
@Override
public void run() {
startWork();
}
}).start();
}

private void startWork(){
Log.v("ljh","这里是客户端,当前进程为:" + pid);

BinderPool instance = BinderPool.getInstance(this);
IBinder iBinderSpeak = instance.queryBinder(BinderPool.BINDER_SPEAK);
iSpeak = ISpeak.Stub.asInterface(iBinderSpeak);

try {
iSpeak.speak();
} catch (RemoteException e) {
e.printStackTrace();
}

IBinder iBinderCalculate = instance.queryBinder(BinderPool.BINDER_CALCULATE);
iCalculate = ICalculate.Stub.asInterface(iBinderCalculate);
try {
iCalculate.add(1,2);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}

注意:这里要在新线程中去执行,因为在Binder连接池的实现,我们通过CountDownLatch将bindService这一异步操作转换成了同步操作,这就意味着它可能是耗时的,同时Binder方法的调用过程也可能是耗时的,因此不建议放在主线程中去执行。

效果

【IPC实战④】Binder连接池_开发语言_03


【IPC实战④】Binder连接池_android_04

3.文章推荐和项目地址

项目地址:​​https://github.com/LJHnb666666/BinderPoolDemo​​


举报

相关推荐

Okhttp连接池

JDBC连接池

Java连接池

HikariCP连接池

MySQL连接池

Jedis连接池

0 条评论