為什么使用HermesEventBus
原有項(xiàng)目場(chǎng)景:Socket通信模塊在子進(jìn)程RemoteService中请毛,主進(jìn)程想要發(fā)送一個(gè)Socket協(xié)議,先從業(yè)務(wù)模塊通過EventBus post一個(gè)Event到本地LocalService聂薪,本地Service通過ServiceConnection與RemoteService綁定家乘,本地LocalService在ServiceConnection的連接上將AIDL接口封裝為一個(gè)Messenger,通過Messenger向RemoteService發(fā)送Message藏澳,而Event就是被包裹在Message中的Bundle里仁锯。
說到這里感覺不借助圖形很難描述:
問題在這里:
- 每個(gè)序列化的Object要放入Bundle中,Bundle對(duì)象再放入Message中翔悠,過程繁瑣
- 每個(gè)Message都有what屬性需要Handler在處理時(shí)判斷
- 業(yè)務(wù)模塊想要執(zhí)行子進(jìn)程的RemoteService的方法先通過EventBus post一個(gè)Object业崖,在LocalService必須有相應(yīng)的處理。
- 子進(jìn)程中的RemoteService接收到了服務(wù)器發(fā)來的消息給業(yè)務(wù)模塊蓄愁,先要通過本地LocalService處理Message双炕,再由EventBus把Message中的Object post出去。
綜上所述撮抓,多了一個(gè)LocalService妇斤,顯得很礙眼。
使用HermesEventBus
HermesEventBus是一種支持跨進(jìn)程丹拯,跨APP通信的以EventBus為基礎(chǔ)的框架站超,使用起來就像EventBus。
項(xiàng)目地址:https://github.com/elemers/HermesEventBus
** 如果你的應(yīng)用是單個(gè)app咽笼,在Application中可以初始化HermesEventBus**:
private void initHermesEventBus() {
HermesEventBus.getDefault().init(getBaseApplication());
}
由于是多進(jìn)程顷编,以我的項(xiàng)目為例戚炫,主進(jìn)程會(huì)跑一遍這個(gè)方法剑刑,RemoteService啟動(dòng)時(shí)子進(jìn)程也會(huì)跑一遍這個(gè)方法。
** 如果項(xiàng)目是多個(gè)app,選擇一個(gè)作為主APP注冊(cè)Service**:
<service android:name="xiaofei.library.hermes.HermesService$HermesService0"/>
然后在其他app的Application的onCreate中執(zhí)行:
HermesEventBus.getDefault().connectApp(this, packageName);
** 當(dāng)進(jìn)程不再需要使用HermesEventBus施掏,通過調(diào)用以下方法銷毀HermesEventBus**:
HermesEventBus.getDefault().destroy();
發(fā)送事件就像EventBus一樣簡(jiǎn)單,在任意進(jìn)程內(nèi)執(zhí)行:
HermesEventBus.getDefault().postSticky(event);
發(fā)送完事件钮惠,在任意進(jìn)程內(nèi)的注冊(cè)的觀察者就會(huì)處理事件:
/**
* 通信層處理發(fā)送SOCKET請(qǐng)求事件
* @param event
*/
@Subscribe(threadMode = ThreadMode.POSTING , sticky = true)
public void handleRequestEvent(RequestEvent event){
onHandleLocalSocketBizRequest(event);
}
HermesEventBus是怎么做到跨進(jìn)程通信的
先看初始化方法:
public void init(Context context) {
mContext = context.getApplicationContext();
mMainProcess = isMainProcess(context.getApplicationContext());
if (mMainProcess) {
Hermes.init(context);
Hermes.register(MainService.class);
mMainApis = MainService.getInstance();
} else {
mState = STATE_CONNECTING;
Hermes.setHermesListener(new HermesListener());
Hermes.connect(context, Service.class);
Hermes.register(SubService.class);
}
}
在初始化時(shí),區(qū)分了主進(jìn)程和子進(jìn)程七芭,如果是子進(jìn)程會(huì)通過Hermes.connect(context, Service.class)綁定主進(jìn)程的Service素挽。
打開編譯好的APK,查看AndroidManifest.xml會(huì)發(fā)現(xiàn):
<service
android:name="xiaofei.library.hermeseventbus.HermesEventBus$Service" />
沒錯(cuò)狸驳,子進(jìn)程就是綁定了主進(jìn)程中的Service與主進(jìn)程通信的预明。而通信的載體是一個(gè)Mail類:
private final IHermesService.Stub mBinder = new IHermesService.Stub() {
@Override
public Reply send(Mail mail) {
try {
Receiver receiver = ReceiverDesignator.getReceiver(mail.getObject());
int pid = mail.getPid();
IHermesServiceCallback callback = mCallbacks.get(pid);
if (callback != null) {
receiver.setHermesServiceCallback(callback);
}
return receiver.action(mail.getTimeStamp(), mail.getMethod(), mail.getParameters());
} catch (HermesException e) {
e.printStackTrace();
return new Reply(e.getErrorCode(), e.getErrorMessage());
}
}
@Override
public void register(IHermesServiceCallback callback, int pid) throws RemoteException {
mCallbacks.put(pid, callback);
}
@Override
public void gc(List<Long> timeStamps) throws RemoteException {
OBJECT_CENTER.deleteObjects(timeStamps);
}
};
public class Mail implements Parcelable {
private long mTimeStamp;
private int mPid;
private ObjectWrapper mObject;
private MethodWrapper mMethod;
private ParameterWrapper[] mParameters;
public static final Parcelable.Creator<Mail> CREATOR
= new Parcelable.Creator<Mail>() {
public Mail createFromParcel(Parcel in) {
Mail mail = new Mail();
mail.readFromParcel(in);
return mail;
}
public Mail[] newArray(int size) {
return new Mail[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeLong(mTimeStamp);
parcel.writeInt(mPid);
parcel.writeParcelable(mObject, flags);
parcel.writeParcelable(mMethod, flags);
parcel.writeParcelableArray(mParameters, flags);
}
public void readFromParcel(Parcel in) {
mTimeStamp = in.readLong();
mPid = in.readInt();
ClassLoader classLoader = Mail.class.getClassLoader();
mObject = in.readParcelable(classLoader);
mMethod = in.readParcelable(classLoader);
Parcelable[] parcelables = in.readParcelableArray(classLoader);
if (parcelables == null) {
mParameters = null;
} else {
int length = parcelables.length;
mParameters = new ParameterWrapper[length];
for (int i = 0; i < length; ++i) {
mParameters[i] = (ParameterWrapper) parcelables[i];
}
}
}
private Mail() {
}
public Mail(long timeStamp, ObjectWrapper object, MethodWrapper method, ParameterWrapper[] parameters) {
mTimeStamp = timeStamp;
mPid = Process.myPid();
mObject = object;
mMethod = method;
mParameters = parameters;
}
public int getPid() {
return mPid;
}
public ParameterWrapper[] getParameters() {
return mParameters;
}
public ObjectWrapper getObject() {
return mObject;
}
public MethodWrapper getMethod() {
return mMethod;
}
public long getTimeStamp() {
return mTimeStamp;
}
}
回顧一下AIDL通信,AIDL接口支持的參數(shù)類型除了基本類型耙箍、List撰糠、Map、AIDL接口就是Parcelable辩昆,而Mail這個(gè)實(shí)現(xiàn)Parcelable的類將Object封裝在內(nèi)部阅酪。
所以HermesEventBus本質(zhì)上也是通過AIDL實(shí)現(xiàn)跨進(jìn)程通信,依賴于主進(jìn)程的Service載體汁针。使用HermesEventBus省去了自己實(shí)現(xiàn)跨進(jìn)程通信的煩惱术辐。
小結(jié)幾種跨進(jìn)程方法
- BroadCastReceiver 由于面向整個(gè)系統(tǒng)注冊(cè)的廣播,跨進(jìn)程消耗較大施无,性能不能保證辉词。
- ContentProvider 支持跨進(jìn)程數(shù)據(jù)共享
- AIDL 客戶端調(diào)用AIDL接口是同步并且?guī)Х祷亟Y(jié)果的,如果執(zhí)行時(shí)間較長(zhǎng)猾骡,客戶端的調(diào)用線程會(huì)一直等待较屿。服務(wù)端執(zhí)行AIDL接口是異步的,支持所有基本類型卓练、AIDL接口隘蝎、Parcelable、List襟企、Map等類型的參數(shù)嘱么,實(shí)現(xiàn)起來繁瑣。
- Messenger 本質(zhì)是AIDL通信顽悼,客戶端發(fā)送Message后不帶返回結(jié)果曼振,服務(wù)端接收到Message是通過一個(gè)線程的Handler輪詢MessageQueue處理的,因此處理Message是在同一線程蔚龙。
- HermesEventBus 本質(zhì)也是AIDL通信冰评,不需要自己實(shí)現(xiàn)綁定Service,發(fā)送事件也是不帶返回結(jié)果的木羹,使用簡(jiǎn)單甲雅。
- Binder機(jī)制 Android跨進(jìn)程通信實(shí)現(xiàn)的核心解孙,AIDL就是基于Binder機(jī)制實(shí)現(xiàn)的,其中transact方法是客戶端向服務(wù)端發(fā)送消息抛人,onTransact方法是客戶端接收服務(wù)端的消息弛姜。