一.前言
由于最近負責小度在家平臺接入咪咕視頻,因為咪咕視頻是第三方的app,這樣就涉及小度query指令透傳到咪咕,咪咕的UIControl需要同步給小度云端的跨進程互相調(diào)用的場景。然后我看項目里又接入了愛奇藝,CIBN等一系列的第三方app,都是通過AIDL方式跨進程調(diào)用的,查看項目發(fā)現(xiàn)每個app對應(yīng)一個Serivce,假如接入30個第三方app,按照項目現(xiàn)有的實現(xiàn)方式就會有30個Service,我們知道Service是系統(tǒng)組件,勢必導致系統(tǒng)開銷。
我們項目提供給第三方的sdk基本是AIDL方式提供接口的,AIDL應(yīng)該很簡單,這里我們回顧下AIDL的大概流程:新建一個Serivce和一個AIDL接口,然后繼承AIDL接口的Stub并實現(xiàn)抽象方法,接著在Service的onBind方法中返回AIDL接口實例,接著客戶端綁定Serivce并將Service#onBind方法IBinder實例傳給ServiceConnection#onServiceConnected中,通過asInterface轉(zhuǎn)成得到接口實例,這樣客戶端就可以調(diào)用服務(wù)端的接口方法了。
二.優(yōu)化方案
基于上面提出的問題,主要是解決Service數(shù)量多的問題,同時每個模塊有自己的AIDL實現(xiàn)接口并且通過BinderPool管理一個AIDL接口用于查詢各模塊的AIDL的IBinder實例,BinderPool對應(yīng)僅僅一個Service,在Service中返回用于獲取Binder連接池里的AIDL接口實例,通過這種機制可以用1個Service、多個AIDL接口的SDK方式對應(yīng)幾乎所有第三方的app接入。我們只要在Service#onBind的AIDL接口區(qū)分不同的標識,通過不同的標識返回對應(yīng)模塊的AIDL接口實例,我們就可以調(diào)用到各自模塊的接口。
Binder池實現(xiàn)
1.新建二個AIDL接口
IMyAidlInterface(獲取一個字符串)如下:
// IMyAidlInterface.aidl
package zw.chowen.binderpool;
// Declare any non-default types here with import statements
interface IMyAidlInterface {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
String getValue();
}
IMyAidlInterface2(獲取兩個整形相加和)如下:
package zw.chowen.binderpool;
// Declare any non-default types here with import statements
interface IMyAidlInterface2 {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
int add(int a, int b);
}
以上兩個AIDL接口對應(yīng)不同的進程。
2.新建AIDL池接口:用于獲取相應(yīng)模塊的的IBinder接口。
IBinderPoolInterface:
// IBinderPoolInterface.aidl
package zw.chowen.binderpool;
// Declare any non-default types here with import statements
interface IBinderPoolInterface {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
IBinder queryInterface(int type);
}
3.分別實現(xiàn)這三個AIDL接口
public class IMyAidlInterfaceImpl extends zw.chowen.binderpool.IMyAidlInterface.Stub {
@Override
public String getValue() throws RemoteException {
return "chowen#this is IMyAidlInterface";
}
}
public class IMyAidlInterfaceImpl2 extends IMyAidlInterface2.Stub {
@Override
public int add(int a, int b) throws RemoteException {
LOGGER.info("chowen#a and b >>" + (a + b));
return a+b;
}
}
public class BinderPoolServiceImpl extends IBinderPoolInterface.Stub {
public BinderPoolServiceImpl() {
super();
}
@Override
public IBinder queryInterface(int type) throws RemoteException {
IBinder binder = null;
switch (type) {
case 1:
binder = new IMyAidlInterfaceImpl();
break;
case 2:
binder = new IMyAidlInterfaceImpl2();
break;
}
return binder;
}
}
分別繼承Stub并實現(xiàn)各自抽象方法,通過IBinderPoolInterface的實現(xiàn)類BinderPoolServiceImpl中queryInterface方法即可返回各自模塊對應(yīng)類型的IBinder對象。
4.創(chuàng)建Service及IBinder池機制
Service
/**
* Created by zhouwen on 2019-10-06 22:30
*/
public class BinderPoolService extends Service {
private static Logger LOGGER = Logger.getLogger("BinderPoolService");
@Nullable
@Override
public IBinder onBind(Intent intent) {
LOGGER.info("chowen#onBind=" + (IBinder) BinderPoolManager.getIns(this).getBinder());
//返回獲取各模塊IBinder的AIDL接口
return (IBinder) BinderPoolManager.getIns(this).getBinder();
}
@Override
public void onCreate() {
LOGGER.info("chowen#onCreate");
LOGGER.severe("chowen#process=" + Process.myPid());
super.onCreate();
}
@Override
public void onDestroy() {
LOGGER.info("chowen#onDestroy");
super.onDestroy();
BinderPoolManager.getIns(this).unbindService(this);
}
}
通過BinderPoolManager綁定BinderPoolService這個服務(wù),然后在BinderPoolService#onBind方法返回IBinderPoolInterface實例。
IBinder池機制:
/**
* Created by zhouwen on 2019-10-06 22:24
* Binder連接池實例
*/
public class BinderPoolManager {
private static Logger LOGGER = Logger.getLogger("BinderPoolManager");
private static BinderPoolManager sBinderPoolManager;
private IBinderPoolInterface mIBinderPoolInterface;
public BinderPoolManager(Context context) {
bindService(context.getApplicationContext());
}
public static BinderPoolManager getIns(Context context) {
if (sBinderPoolManager == null) {
synchronized (BinderPoolManager.class) {
if (sBinderPoolManager == null) {
sBinderPoolManager = new BinderPoolManager(context);
}
}
}
return sBinderPoolManager;
}
public class IMyAidlInterfaceImpl extends zw.chowen.binderpool.IMyAidlInterface.Stub {
@Override
public String getValue() throws RemoteException {
return "chowen#this is IMyAidlInterface";
}
}
public class IMyAidlInterfaceImpl2 extends IMyAidlInterface2.Stub {
@Override
public int add(int a, int b) throws RemoteException {
LOGGER.info("chowen#a and b >>" + (a + b));
return a+b;
}
}
public IBinder queryInterface(int type) {
try {
LOGGER.info("chowen#queryInterface#mIBinderPoolInterface>>" + mIBinderPoolInterface);
if (mIBinderPoolInterface != null) {
return mIBinderPoolInterface.queryInterface(type);
}
} catch (RemoteException e) {
e.printStackTrace();
}
return null;
}
public class BinderPoolServiceImpl extends IBinderPoolInterface.Stub {
public BinderPoolServiceImpl() {
super();
}
@Override
public IBinder queryInterface(int type) throws RemoteException {
IBinder binder = null;
switch (type) {
case 1:
binder = new IMyAidlInterfaceImpl();
break;
case 2:
binder = new IMyAidlInterfaceImpl2();
break;
}
return binder;
}
}
public synchronized void bindService(Context context) {
Intent intent = new Intent(context, BinderPoolService.class);
context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
}
public IBinderPoolInterface getBinder() {
return new BinderPoolServiceImpl();
}
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mIBinderPoolInterface = IBinderPoolInterface.Stub.asInterface(service);
LOGGER.info("chowen#onServiceConnected#mIBinderPoolInterface="+ mIBinderPoolInterface);
}
@Override
public void onServiceDisconnected(ComponentName name) {
LOGGER.info("chowen#onServiceDisconnected");
}
};
public void unbindService(Context context){
context.unbindService(serviceConnection);
}
}
5.模擬多進程實現(xiàn)
我們在AndroidManifest文件中聲明多個進程,這里就隨便申請如下:
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".SecondActivity"
android:process=":other" />
<service
android:name=".BinderPoolService"
android:process=":binder_pool" />
</application>
我們通過主進程,other進程分別調(diào)用相應(yīng)的接口方法。
主進程:
IBinder binder = mBinderPoolManager.queryInterface(1);
IMyAidlInterface iMyAidlInterface1 = BinderPoolManager.IMyAidlInterfaceImpl.asInterface(binder);
LOGGER.info("chowen#onResume#iMyAidlInterface1=" + iMyAidlInterface1);
if (iMyAidlInterface1 != null) {
try {
LOGGER.info("chowen#onResume#value=" + iMyAidlInterface1.getValue());
} catch (RemoteException e) {
e.printStackTrace();
}
}
other進程:
IBinder binder = mBinderPoolManager.queryInterface(2);
IMyAidlInterface2 iMyAidlInterface2 = BinderPoolManager.IMyAidlInterfaceImpl2.asInterface(binder);
LOGGER.info("chowen#iMyAidlInterfaceImpl2=" + iMyAidlInterface2);
if (iMyAidlInterface2 != null) {
try {
LOGGER.info("chowen#a and b is>>>" + iMyAidlInterface2.add(10, 20));
} catch (RemoteException e) {
e.printStackTrace();
}
}
分別通過BinderPoolManager#queryInterface方法通過各自的標識類型,這里用1,2表示,去分別獲取IBinderPoolInterface接口實現(xiàn)中對應(yīng)的IBinder實例。
6.IBinder池執(zhí)行效果:
2019-10-07 00:03:04.106 16689-16689/? E/MainActivity: chowen#process=16689
2019-10-07 00:03:04.185 16725-16725/? I/BinderPoolService: chowen#onCreate
2019-10-07 00:03:04.186 16725-16725/? E/BinderPoolService: chowen#process=16725
2019-10-07 00:03:04.189 16725-16725/? I/BinderPoolService: chowen#onBind=zw.chowen.binderpool.BinderPoolManager$BinderPoolServiceImpl@c1109bc
2019-10-07 00:03:04.191 16725-16725/? I/BinderPoolManager: chowen#onServiceConnected#mIBinderPoolInterface=zw.chowen.binderpool.BinderPoolManager$BinderPoolServiceImpl@7a09d45
2019-10-07 00:03:04.312 16689-16689/? I/BinderPoolManager: chowen#onServiceConnected#mIBinderPoolInterface=zw.chowen.binderpool.IBinderPoolInterface$Stub$Proxy@4283e77
2019-10-07 00:03:10.127 16689-16689/? I/BinderPoolManager: chowen#queryInterface#mIBinderPoolInterface>>zw.chowen.binderpool.IBinderPoolInterface$Stub$Proxy@4283e77
2019-10-07 00:03:10.132 16689-16689/? I/MainActivity: chowen#onResume#iMyAidlInterface1=zw.chowen.binderpool.IMyAidlInterface$Stub$Proxy@2a9f150
2019-10-07 00:03:10.134 16689-16689/? I/MainActivity: chowen#onResume#value=chowen#this is IMyAidlInterface
2019-10-07 00:03:13.119 16761-16761/? E/SecondActivity: chowen#process=16761
2019-10-07 00:03:13.140 16761-16761/? I/BinderPoolManager: chowen#onServiceConnected#mIBinderPoolInterface=zw.chowen.binderpool.IBinderPoolInterface$Stub$Proxy@b36e1c0
2019-10-07 00:03:17.126 16761-16761/? I/BinderPoolManager: chowen#queryInterface#mIBinderPoolInterface>>zw.chowen.binderpool.IBinderPoolInterface$Stub$Proxy@b36e1c0
2019-10-07 00:03:17.128 16761-16761/? I/SecondActivity: chowen#iMyAidlInterfaceImpl2=zw.chowen.binderpool.IMyAidlInterface2$Stub$Proxy@2c1fa84
2019-10-07 00:03:17.130 16725-16740/? I/BinderPoolManager: chowen#a and b >>30
2019-10-07 00:03:17.130 16761-16761/? I/SecondActivity: chowen#a and b is>>>30
我們從Log看出分別處于不同兩個進程,通過自己的AIDL接口分別打印出預(yù)期結(jié)果,并且Bind一個Service。
三.總結(jié)
通過Binder連接池機制可以很好的解決項目中多個Service的問題,降低系統(tǒng)創(chuàng)建Service的開銷。通過一個AIDL接口對外提供獲取相應(yīng)模塊的AIDL的接口實例。
步驟如下:
1.創(chuàng)建各自的AIDL文件并實現(xiàn)對應(yīng)接口。
2.創(chuàng)建提供獲取AIDL接口的AIDL文件。
3.創(chuàng)建AIDL連接池,主要用于啟動服務(wù),生成IBinder對象等。
4.創(chuàng)建1個Service,通過AIDL連接池獲取對外的AIDL接口實例在onBind方法中返回。
流程如下:

Demo實現(xiàn):binderpool