前面转载了一篇AIDL的入门文章,从那时开始接触的AIDL。
AIDL的使用一般是一个客户端,一个服务端。服务端返回一个AIDL接口,客户端拿到该接口调用方法。
但是,如果项目中有大量的AIDL文件,那么就要建相应个数的Service,这显然是不合理,现在介绍一种方法,优化AIDL的使用。先帖服务端的目录结构图
MainActivity是默认的,没添加任何代码,直接忽略。首先先看三个AIDL文件,都是很简单的。
ICompute.aidl文件代码为:
interface ICompute { int add(int a,int b); },只定义了一个方法。
ISecurityCenter.aidl文件代码:
interface ISecurityCenter { String encrypt(String content); String decrypt(String password); },定义两个方法,加密跟解密
IBinderPool.aidl文件代码为:
interface IBinderPool { IBinder queryBinder(int binderCode); },这个是本次博客的重点,通过该接口来达到需要的结果。 服务端返回这个接口给客服端,客服端需要的其他任何接口都是通过调用IBinderPool接口的queryBinder方法返回的。
然后再看三个JAVA类的代码
public class ComputeImpl extends ICompute.Stub { @Override public int add(int a, int b) throws RemoteException { return a+b; } }是AIDL文件ICompute的实现类;
public class SecurityCenterImpl extends Stub{ private static final char SECRET_CODE='^'; @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); } }是AIDL文件ISecurityCenter的实现类,这两个类的作用就是实现接口中的方法,以便于客户端调用。BinderPoolService类则是唯一的Service类,客户端就是通过与该Service类绑定从而得到的IBinderPool接口。通过调用IBinderPool这个接口中的queryBinder方法,达到根据传入不同的code得到不同的AIDL接口。
BinderService.java代码:
public class BinderPoolService extends Service { public static final int BINDER_COMPUTE = 0; public static final int BINDER_SECURITY_CENTER = 1; private static final String TAG="BinderPoolService"; private Binder mBinderPool = new IBinderPool.Stub() { @Override 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; } }; @Nullable @Override public IBinder onBind(Intent intent) { return mBinderPool; } @Override public void onCreate() { super.onCreate(); } @Override public void onDestroy() { super.onDestroy(); } }
这个Service类也很简单,首先是实现IBinderPool接口,并实现其中的queryBinder方法,方法中根据不同的binderCode生成不同的AIDL接口,并返回。Service主要是在OnBind方法中IBinderPool接口返回。到此,服务端就完成了,再来看看客服端的代码,也很简单,首先目录结构。写代码前首先把服务端的AIDL文件夹整个拷贝过来。然后看看BinderPool的代码:
public 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; public Context mContext; private IBinderPool mBinderPool; private static volatile BinderPool sInstance; private CountDownLatch mConnectBinderPoolCountDownLatch; private BinderPool(Context context) { mContext = context.getApplicationContext(); connectBinderPoolService(); } 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 intent = new Intent(); intent.setAction("com.lypeer.aidl1"); intent.setPackage("com.example.administrator.aidlserviceone"); mContext.bindService(intent, 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) { Log.i("--->","连接成功"); mBinderPool = IBinderPool.Stub.asInterface(service); try { mBinderPool.asBinder().linkToDeath(mBinderPoolDeathRecipient, 0); } catch (RemoteException e) { e.printStackTrace(); } mConnectBinderPoolCountDownLatch.countDown(); } @Override public void onServiceDisconnected(ComponentName name) { Log.i("--->","连接失败"); } }; private IBinder.DeathRecipient mBinderPoolDeathRecipient = new IBinder.DeathRecipient() { @Override public void binderDied() { mBinderPool.asBinder().unlinkToDeath(mBinderPoolDeathRecipient, 0); mBinderPool = null; connectBinderPoolService(); } }; }这个相当于工具类,负责绑定服务端的Service,以及获取其他的AIDL接口。
MainActivity.java代码:
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); findViewById(R.id.button).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { new Thread(new Runnable() { @Override public void run() { doWork(); } }).start(); } }); } private void doWork(){ BinderPool binderPool=BinderPool.getInstance(MainActivity.this); IBinder securityBinder=binderPool.queryBinder(BinderPool.BINDER_SECURITY_CENTER); ISecurityCenter mSecurityCenter= ISecurityCenter.Stub.asInterface(securityBinder); String msg="helloword-安卓"; try { String password=mSecurityCenter.encrypt(msg); Log.i("---->",password); } catch (RemoteException e) { e.printStackTrace(); } IBinder computeBinder=binderPool.queryBinder(BinderPool.BINDER_COMPUTE); ICompute mCompute=ICompute.Stub.asInterface(computeBinder); try { Log.i("3+5--->",""+ mCompute.add(3,5)); } catch (RemoteException e) { e.printStackTrace(); } } }主要是执行work方法。
好了,运行起来看一看吧。如果要添加AIDL问价,只需要在服务端的Service里queryBinder方法中添加一个bindercode,当然还有一点比较重要,就是服务端和客户端要约定好不同的AIDL文件对应不同的一个bindercode,而且两端的bindercode要一致,才能保证一一对应。