1.Binder连接池
💡 使用原因:针对多个使用AIDL进行跨进程通信的环境下,不可能对每一个跨进程通信都新建Service连接,这样会给系统资源带来损耗,同时,也会难以维护管理,针对于这种情况下,需要使用Binder连接池来进行管理。
1.1Binder连接池工作机制
💡 如图所示,可以新建一个Service对这些Binder连接进行管理,当需要某个连接时直接返回相对应的连接,说白了就是新建一个AIDL连接,通过这个连接去管理所有的业务,从而避免重复连接。
1.2 代码实现
- 需要binder的业务模块
// ISecurityCenter.aidl
package com.example.artandroidlearn;
// Declare any non-default types here with import statements
interface ISecurityCenter {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
String encrypt(String content);
String decrypt(String password);
}
package com.example.artandroidlearn;
import android.os.RemoteException;
public class SecurityCenterImpl extends ISecurityCenter.Stub {
private static final char SECRET_CODE = '^';
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
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);
}
@Override
public String decrypt(String password) throws RemoteException {
return encrypt(password);
}
}
// ICompute.aidl
package com.example.artandroidlearn;
// Declare any non-default types here with import statements
interface ICompute {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
int add(int a,int b);
}
package com.example.artandroidlearn;
import android.os.RemoteException;
public class ComputeImpl extends ICompute.Stub {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public int add(int a, int b) throws RemoteException {
return a + b;
}
}
- binder连接池实现
// IBinderPool.aidl
package com.example.artandroidlearn;
// Declare any non-default types here with import statements
interface IBinderPool {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
IBinder queryBinder(int binderCode);
}
package com.example.artandroidlearn.Service;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import androidx.annotation.Nullable;
import com.example.artandroidlearn.BinderPool;
public class BinderPoolService extends Service {
private static final String TAG = "BinderPoolService";
private BinderPool.BinderPoolImpl mBinderPool = new BinderPool.BinderPoolImpl();
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBinder");
return mBinderPool;
}
}
package com.example.artandroidlearn;
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 android.util.Log;
import com.example.artandroidlearn.Service.BinderPoolService;
import java.util.concurrent.CountDownLatch;
public class BinderPool {
private static final String TAG = "BinderPool";
public static final int BINDER_NONE = -1;
public static final int BINDER_COMPUTER = 0;
public static final int BINDER_SECURITY_CENTER = 1;
private Context mContext;
private IBinderPool mBinderPool;
private static volatile BinderPool sInstance;
private CountDownLatch mConnectBinderPoolCountDownLatch;
public BinderPool(Context context) {
this.mContext = context.getApplicationContext();
connectBinderPoolService();
}
public static BinderPool getInstance(Context context) {
if (sInstance == null) {
synchronized (BinderPool.class) {
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();
}
}
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();
}
mConnectBinderPoolCountDownLatch.countDown();
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
private IBinder.DeathRecipient mBinderPoolDeathRecipient = new IBinder.DeathRecipient() {
@Override
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();
}
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public IBinder queryBinder(int binderCode) throws RemoteException {
IBinder binder = null;
switch (binderCode) {
case BINDER_SECURITY_CENTER:
binder = new SecurityCenterImpl();
break;
case BINDER_COMPUTER:
binder = new ComputeImpl();
break;
default:
break;
}
return binder;
}
}
}
💡 这里使用CountDownLatch
将异步操作变成了同步操作,因此在客户端实现需要将相应操作放在子线程里面去执行,防止调用过程耗时,此外BinderPool
是一个单实例,只会实例化一次,不管有多少个连接,都只有这一个Service
,另外这里设置了断线重连机制,因此断开会自动重连。
- 客户端实现
package com.example.artandroidlearn.activity;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import com.example.artandroidlearn.BinderPool;
import com.example.artandroidlearn.ComputeImpl;
import com.example.artandroidlearn.ICompute;
import com.example.artandroidlearn.ISecurityCenter;
import com.example.artandroidlearn.R;
import com.example.artandroidlearn.SecurityCenterImpl;
public class BinderPoolActivity extends AppCompatActivity {
private static final StringTAG= "BinderPoolActivity";
private ISecurityCenter mSecurityCenter;
private ICompute mICompute;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_binder_pool);
new Thread(new Runnable() {
@Override
public void run() {
doWork();
}
}).start();
}
public void doWork() {
BinderPool binderPool = BinderPool.getInstance(this);
IBinder securityBinder = binderPool.queryBinder(BinderPool.BINDER_SECURITY_CENTER);
mSecurityCenter = (ISecurityCenter) SecurityCenterImpl.asInterface(securityBinder);
Log.d(TAG, "visit center");
try {
String password = mSecurityCenter.encrypt("wenghailin");
Log.d(TAG, password);
Log.d(TAG, mSecurityCenter.decrypt(password));
} catch (RemoteException e) {
e.printStackTrace();
}
Log.d(TAG, "visit compute");
IBinder computeBinder = binderPool.queryBinder(BinderPool.BINDER_COMPUTER);
mICompute = (ICompute) ComputeImpl.asInterface(computeBinder);
try {
Log.d(TAG, Integer.toString(mICompute.add(1, 2)));
} catch (RemoteException e) {
e.printStackTrace();
}
}
}