1. aidl實(shí)現(xiàn)流程概述
首先建立一個(gè)aidl接口和一個(gè)Service抬探,接著實(shí)現(xiàn)一個(gè)類A繼承aidl接口中的Stub類并實(shí)現(xiàn)其中的方法子巾,在Service綁定時(shí)返回類A的對象,然后客戶端就可以綁定服務(wù)端,建立連接后就可以訪問遠(yuǎn)程服務(wù)端的方法了线梗。
2. 可能出現(xiàn)的問題及解決方式
公司項(xiàng)目越來越大椰于,100個(gè)aidl,按照上面的思路缠导,得100個(gè)Service廉羔。這顯然不可以,解決方式是binder 連接池僻造。
整個(gè)工作機(jī)制是這樣的:每個(gè)業(yè)務(wù)模塊創(chuàng)建自己的aidl接口并實(shí)現(xiàn)此接口憋他,這個(gè)時(shí)候不同業(yè)務(wù)模塊之間是不能有耦合的,然后向服務(wù)端提供自己的唯一標(biāo)識和其對應(yīng)的Binder對象髓削;對于服務(wù)端來說竹挡,只需要一個(gè)Service,服務(wù)端提供一個(gè)queryBinder接口立膛,這個(gè)接口能夠根據(jù)業(yè)務(wù)模塊特征來返回相應(yīng)的Binder對象給他們揪罕,不同的業(yè)務(wù)模塊拿到所需的Binder對象后就可以進(jìn)行遠(yuǎn)程方法調(diào)用了。
Binder連接池的主要作用就是將每個(gè)業(yè)務(wù)模塊的Binder請求同一轉(zhuǎn)發(fā)到遠(yuǎn)程Service中去宝泵,避免重復(fù)創(chuàng)建Service的過程好啰。
3. 定義兩個(gè)業(yè)務(wù)aidl接口并實(shí)現(xiàn)
package qingfengmy.developmentofart._2activity.binderpool.aidl;
interface ICompute {
int add(int a, int b);
}
// ISecurityCenter.aidl
package qingfengmy.developmentofart._2activity.binderpool.aidl;
interface ISecurityCenter {
String encrypt(in String content);
String decrypt(in String password);
}
public class SecurityCenterImpl extends ISecurityCenter.Stub {
@Override
public String encrypt(String content) throws RemoteException {
char[] chars = content.toCharArray();
for (int i=0; i<chars.length;i++) {
chars[i] = (char) (chars[i]+1);
}
return new String(chars);
}
@Override
public String decrypt(String password) throws RemoteException {
char[] chars = password.toCharArray();
for (int i=0; i<chars.length;i++) {
chars[i] = (char) (chars[i]-1);
}
return new String(chars);
}
}
public class ComputerImpl extends ICompute.Stub {
@Override
public int add(int a, int b) throws RemoteException {
return a+b;
}
}
4. 定義BinderPool接口并實(shí)現(xiàn)
package qingfengmy.developmentofart._2activity.binderpool.aidl;
interface IBinderPool {
IBinder queryBinder(int binderCode);
}
public static class BinderPoolImpl extends IBinderPool.Stub{
@Override
public IBinder queryBinder(int binderCode) throws RemoteException {
switch (binderCode) {
case 0:
return new SecurityCenterImpl();
case 1:
return new ComputerImpl();
}
return null;
}
}
5. 服務(wù)實(shí)現(xiàn)
public class PoolService extends Service {
private Binder mBinderPool = new BinderPool.BinderPoolImpl();
public PoolService() {
}
@Override
public IBinder onBind(Intent intent) {
return mBinderPool;
}
}
6. BinderPool的實(shí)現(xiàn)
public class BinderPool {
// 定義BinderCode
private static final int BINDER_NONE = -1;
public static final int BINDER_COMPUTE = 0;
public static final int BINDER_SECURITY_CENTER = 1;
private Context mContext;
private IBinderPool mBinderPool;
// volatile 用來修飾被不同線程訪問和修改的變量
private static volatile BinderPool sInstance;
/**
* CountDownLatch類是一個(gè)同步計(jì)數(shù)器,構(gòu)造時(shí)傳入int參數(shù),該參數(shù)就是計(jì)數(shù)器的初始值,每調(diào)用一次countDown()方法儿奶,計(jì)數(shù)器減1,計(jì)數(shù)器大于0 時(shí)框往,await()方法會阻塞程序繼續(xù)執(zhí)行
* CountDownLatch如其所寫,是一個(gè)倒計(jì)數(shù)的鎖存器闯捎,當(dāng)計(jì)數(shù)減至0時(shí)觸發(fā)特定的事件椰弊。利用這種特性,可以讓主線程等待子線程的結(jié)束瓤鼻。
*/
private CountDownLatch mConnectBinderPoolCountDownLatch;
private BinderPool(Context context) {
mContext = context.getApplicationContext();
connectBinderPoolService();
}
public static BinderPool getsInstance(Context context) {
if (sInstance == null) {
synchronized (BinderPool.class) {
if (sInstance == null) {
sInstance = new BinderPool(context);
}
}
}
return sInstance;
}
public IBinder queryBinder(int binderCode) {
try {
return mBinderPool.queryBinder(binderCode);
} catch (RemoteException e) {
e.printStackTrace();
}
return null;
}
private synchronized void connectBinderPoolService() {
// 只有一個(gè)線程有效
mConnectBinderPoolCountDownLatch = new CountDownLatch(1);
Intent intent = new Intent(mContext, PoolService.class);
mContext.bindService(intent, mBinderPoolConnection, Context.BIND_AUTO_CREATE);
// 等待秉版,直到CountDownLatch中的線程數(shù)為0
mConnectBinderPoolCountDownLatch.await();
}
private ServiceConnection mBinderPoolConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mBinderPool = IBinderPool.Stub.asInterface(service);
mBinderPool.asBinder().linkToDeath(mBinderPoolDeathRecipient, 0);
// 執(zhí)行一次countDown,其計(jì)數(shù)減一
mConnectBinderPoolCountDownLatch.countDown();
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
private IBinder.DeathRecipient mBinderPoolDeathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
// 解除死亡綁定
mBinderPool.asBinder().unlinkToDeath(mBinderPoolDeathRecipient, 0);
mBinderPool = null;
// 重連
connectBinderPoolService();
}
};
public static class BinderPoolImpl extends IBinderPool.Stub {
@Override
public IBinder queryBinder(int binderCode) throws RemoteException {
switch (binderCode) {
case BINDER_SECURITY_CENTER:
return new SecurityCenterImpl();
case BINDER_COMPUTE:
return new ComputerImpl();
}
return null;
}
}
}
7. Activity中調(diào)用
private void doWork() {
BinderPool binderPool = BinderPool.getsInstance(this);
IBinder computeBinder = binderPool.queryBinder(BinderPool.BINDER_COMPUTE);
ICompute compute = ComputerImpl.asInterface(computeBinder);
try {
int result = compute.add(1, 2);
Log.e("aaa", "1+2=" + result);
} catch (RemoteException e) {
e.printStackTrace();
}
IBinder securityCenterBinder = binderPool.queryBinder(BinderPool.BINDER_SECURITY_CENTER);
ISecurityCenter iSecurityCenter = SecurityCenterImpl.asInterface(securityCenterBinder);
try {
String content = "i love this book";
Log.e("aaa","加密前:"+content);
content = iSecurityCenter.encrypt(content);
Log.e("aaa","加密后:"+content);
content = iSecurityCenter.decrypt(content);
Log.e("aaa","解密后:"+content);
} catch (RemoteException e) {
e.printStackTrace();
}
}
普通寫法
public void onServiceConnected(ComponentName name, IBinder service) {
iBookManager = IBookManager.Stub.asInterface(service);
}
可見使用BinderPool客戶端中的處理還是一樣茬祷,通過Stub的asInterface方法把IBinder轉(zhuǎn)為業(yè)務(wù)接口清焕。
這樣有新業(yè)務(wù)aidl時(shí),只需加aidl_code牲迫,并在queryBinder中增加返回的aidl即可耐朴。不需寫Servicce,所以如果使用aidl盹憎,必須推薦使用BinderPool模式。