Android IPC程序間通訊(七) Binder連線池
阿新 • • 發佈:2018-11-11
Binder管家之Binder連線池
IPC程序間通訊(四)之AIDL中的AIDL由一個Service進行管理,若是建立10個AIDL業務模組是不是也要建立10個Service來進行管理,那100個呢?顯然繁瑣,怎麼辦麼,用Binder連線池呀!
工作機制:
1.每個業務模組建立其AIDL介面並實現此介面生成具有唯一標識的Binder。
2.Binder連線池將每個業務模組的Binder統一轉發給遠端Service。
3.遠端Service只需建立一個,並提供一個queryBinder介面,此介面根據業務模組的標識來返回相應的Binder給客戶端,客戶端即可進行遠端方法呼叫。
一,建立業務模組AIDL
package com.example.binderpooltest;
//加法功能
interface IPlus {
int plus(int a,int b);
}
package com.example.binderpooltest;
//乘法功能
interface IMultiply {
int multiply(int a,int b);
}
建立一個連線池的AIDL介面queryBinder用於根據業務模組的標識來返回相應的Binder給請求者
package com.example.binderpooltest;
//連線池依binderCode查詢Binder的介面
interface IBinderPool {
IBinder queryBinder(int binderCode);
}
二,建立子類繼承自己的AIDL生成Binder
命名規則 xxImple
先make project 一下生成AIDL對應的 xxx.java檔案
路徑\app\build\generated\source\aidl\debug\包名\xxx.java
package com.example.binderpooltest;
import android.os.RemoteException;
/**
* 實現AIDL業務模組的Binder
* IPlus為自定義AIDL生成的java類
* public static abstract class Stub extends android.os.Binder implements com.example.binderpooltest.IPlus
* Stub繼承自Binder所以IPlus.Stub即為Binder
* 所以IPlusImple也是一個Binder
*/
public class IPlusImple extends IPlus.Stub {
@Override
public int plus(int a, int b) throws RemoteException {
return a + b;
}
}
package com.example.binderpooltest;
import android.os.RemoteException;
public class IMultiplyImple extends IMultiply.Stub {
@Override
public int multiply(int a, int b) throws RemoteException {
return a * b;
}
}
三,建立BinderPool類作為連線池
知識點:
1.雙鎖實現單例項
2.共享鎖CountDownLatch實現同步
3.IBinder.DeathRecipient實現服務斷開重連
public class BinderPool {
private static final String TAG = "DEBUG-WCL: " + BinderPool.class.getSimpleName();
public static final int BINDER_CODE_ONE = 0;
public static final int BINDER_CODE_TWO = 1;
//自定義ADIL生成的IBinderPool.java類
private IBinderPool mBinderPool;
//第一鎖volatile全域性可見
private static volatile BinderPool sInstance;
private Context mContext;
// 同步機制
private CountDownLatch mCountDownLatch;
private BinderPool(Context context) {
mContext = context.getApplicationContext();
connectBinderPoolService();
}
// 單例
public static BinderPool getInstance(Context context) {
if (sInstance == null) {
//第二鎖synchronized
synchronized (BinderPool.class) {
if (sInstance == null) {
sInstance = new BinderPool(context);
}
}
}
return sInstance;
}
// Binder的服務連線
private ServiceConnection mBinderPoolConnection = new ServiceConnection() {
@Override public void onServiceConnected(ComponentName name, IBinder service) {
//以服務返回的IBinderPoolImple-Binder生成IBinderPool物件
mBinderPool = IBinderPool.Stub.asInterface(service);
try {
mBinderPool.asBinder().linkToDeath(mDeathRecipient, 0);
} catch (RemoteException e) {
e.printStackTrace();
}
//設定次數減一,此時為零,下一個開始連線
mCountDownLatch.countDown();
}
@Override public void onServiceDisconnected(ComponentName name) {
}
};
// 繫結服務池
private synchronized void connectBinderPoolService() {
//排隊連線,設定呼叫一次countDown()後,前一個連線斷開,後一個開始連線
mCountDownLatch = new CountDownLatch(1);
Intent service = new Intent(mContext, BinderService.class);
mContext.bindService(service, mBinderPoolConnection, Context.BIND_AUTO_CREATE);
try {
//其餘等待
mCountDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 失效重聯機制, 當Binder死亡時, 重新連線
private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
@Override public void binderDied() {
Log.d(TAG, "Binder失效");
mBinderPool.asBinder().unlinkToDeath(mDeathRecipient, 0);
mBinderPool = null;
connectBinderPoolService();
}
};
/**
* 用於被客戶端呼叫,請求Binder ,最終為向服務端請求
* 此時的mBinderPool為連結服務時從服務返回的IBinderPoolImple-Binder生成的IBinderPool介面
* 即可呼叫介面方法queryBinder(binderCode)即回掉到IBinderPoolImple.queryBinder(int binderCode)
* @param binderCode binder程式碼
* @return Binder
*/
public IBinder queryForBinder(int binderCode) {
IBinder binder = null;
try {
if (mBinderPool != null) {
binder = mBinderPool.queryBinder(binderCode);
}
} catch (RemoteException e) {
e.printStackTrace();
}
return binder;
}
/**
* 用於被服務端呼叫,執行與服務端,當客戶端向BinderPool發起Binder請求,BinderPool向服務請求,返回Binder給客戶端
* public static abstract class Stub extends android.os.Binder implements com.example.binderpooltest.IBinderPool
* IBinderPool.Stub實現了AIDL介面IBinderPool
* IBinderPoolImple繼承IBinderPool.Stub,所以IBinderPoolImple重寫了AIDL介面方法,若其他地方呼叫
* IBinderPool.queryBinder(binderCode)即會回撥到此方法
*/
public static class IBinderPoolImple extends IBinderPool.Stub {
@Override
public IBinder queryBinder(int binderCode) throws RemoteException {
IBinder iBinder = null;
switch (binderCode) {
case BINDER_CODE_ONE:
iBinder = new IPlusImple();
break;
case BINDER_CODE_TWO:
iBinder = new IMultiplyImple();
break;
}
return iBinder;
}
}
}
四,建立服務用於管理BinderPool傳送過來的Binder
public class BinderService extends Service {
public BinderService() {
}
@Override
public void onCreate() {
super.onCreate();
}
//呼叫BinderPool中的,AIDL查詢介面queryBinder的實現類,其中實現了依binderCode返回Binder的方法
//將此IBinder返回給BinderPool
private IBinder mBinder = new BinderPool.IBinderPoolImple();
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
五,前臺客戶端實現
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
//請求Binder的唯一標識
public static final int METHOD_CODE_ONE = 1;
public static final int METHOD_CODE_TWO = 2;
private Context mContext;
private BinderPool mBinderPool;
//請求並希望返回的IBinder
private IBinder mPlusBinder;
private IBinder mMultuplyBinder;
//以返回的IBinder建立的介面
private IPlus mIPlus;
private IMultiply mIMultiply;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext = getApplicationContext();
new Thread(new doWork()).start();
}
private class doWork implements Runnable {
public doWork() {
super();
}
@Override
public void run() {
int a = 2;
int b = 5;
Log.d(TAG, "doWork: 1");
//建立BinderPool單例項
mBinderPool = BinderPool.getInstance(mContext);
Log.d(TAG, "doWork: 2");
try {
//請求的IBinder
mPlusBinder = mBinderPool.queryForBinder(METHOD_CODE_ONE);
Log.d(TAG, "doWork: 3");
//以返回的IBinder建立介面
mIPlus = IPlusImple.asInterface(mPlusBinder);
//呼叫遠端方法
int result1 = mIPlus.plus(a, b);
mMultuplyBinder = mBinderPool.queryForBinder(METHOD_CODE_TWO);
mIMultiply = IMultiplyImple.asInterface(mMultuplyBinder);
int result2 = mIMultiply.multiply(a, b);
Toast.makeText(mContext, "a + b = " + result1 + "/n" +
"a × b = " + result2, Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
}