大家好,我系蒼王。
以下是我這個系列的相關(guān)文章加袋,有興趣可以參考一下盯蝴,可以給個喜歡或者關(guān)注我的文章毅哗。
[Android]如何做一個崩潰率少于千分之三噶應(yīng)用app--章節(jié)列表
組件化群1已經(jīng)滿員,進來的可以加群2 763094035
上一節(jié)捧挺,介紹了使用AIDL的進程通信框架虑绵。
這一節(jié)給大家介紹Messenger的通信框架,而Messenger其意思是“信使”的意思
使用Messenger的優(yōu)勢在于
1.實際傳遞的是Message闽烙,可以復(fù)用信息池
2.支持信息回調(diào)
3.不需要編寫aidl
Messenger繼承了Parcelable接口翅睛,可以作為序列化對象用于傳輸。
這里可以傳入Handler黑竞,Handler里面有包含IMessenger對象
/**
* Create a new Messenger pointing to the given Handler. Any Message
* objects sent through this Messenger will appear in the Handler as if
* {@link Handler#sendMessage(Message) Handler.sendMessage(Message)} had
* been called directly.
*
* @param target The Handler that will receive sent messages.
*/
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
或者傳入IBinder對象捕发,Stub當(dāng)中存在IMessenger對象
/**
* Create a Messenger from a raw IBinder, which had previously been
* retrieved with {@link #getBinder}.
*
* @param target The IBinder this Messenger should communicate with.
*/
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}
實際上Handler中IMessager實現(xiàn)對象是MessengerImpl
final IMessenger getIMessenger() {
synchronized (mQueue) {
if (mMessenger != null) {
return mMessenger;
}
mMessenger = new MessengerImpl();
return mMessenger;
}
}
這里IMessenger是調(diào)用Handler的send方法來發(fā)送消息的。
private final class MessengerImpl extends IMessenger.Stub {
public void send(Message msg) {
msg.sendingUid = Binder.getCallingUid();
Handler.this.sendMessage(msg);
}
}
每個Message當(dāng)中也包含了一個replyTo的變量用戶回調(diào)
/**
* Optional Messenger where replies to this message can be sent. The
* semantics of exactly how this is used are up to the sender and
* receiver.
*/
public Messenger replyTo;
就這幾個步驟Messenger獨立的實現(xiàn)了Parcelable和使用aidl的通信方式
接下來我們介紹一下Modular框架是用Messenger通信設(shè)計很魂。
不同于上一節(jié)介紹的ModularArchitecture的aidl中通信是1對1的通信扎酷,Modular提供的通信框架是通過1對多的發(fā)送方式來傳遞的。
以下是Messenger的注冊流程圖
1.每個模塊初始化時啟動一個消息隊列來監(jiān)聽消息遏匆。
@Override
public void init() {
mBaseModule = this;
//啟動線程接收消息
mWorkThread = new WorkThread();
mWorkThread.start();
//注冊跳轉(zhuǎn)路由
OkBus.getInstance().register(Constants.ROUTER_OPEN_URL, new Event() {
@Override
public void call(Message msg) {
String url = (String) msg.obj;
//實際跳轉(zhuǎn)使用的Router
Router.openLocalUrl(BaseAppModuleApp.getBaseApplication(), url);
}
}, Bus.UI); //線程參數(shù)
}
public class WorkThread extends Thread {
Handler mHandler;
public Messenger clientHandler;
@Override
public void run() {
Looper.prepare();
//每個module都有接收消息處理ClientHandler
mHandler = new ClientHandler();
clientHandler = new Messenger(mHandler);
if(resultRef!=null){
try {
resultRef.set(clientHandler);
} catch (Exception e) {
e.printStackTrace();
} finally {
//使用CountDownLatch喚醒機制保證線程安全
latch.countDown();
}
}
Looper.loop();
}
public void quit() {
mHandler.getLooper().quit();
}
}
2.綁定MessengerService作為進程間管理法挨,并且綁定每個模塊的ServiceConnection
/**
* 連接服務(wù)器
*/
public void connectService() {
Intent intent = new Intent(MessengerService.class.getCanonicalName());// 5.0+ need explicit intent
intent.setPackage(Constants.SERVICE_PACKAGE_NAME); // the package name of Remote Service
//綁定MessengerService作為進程間管理,并且綁定每個模塊的ServiceConnection
boolean mIsBound = bindService(intent, mBaseModule.mConnection, BIND_AUTO_CREATE);
LogUtils.i(Constants.TAG + " connectService", " ServiceConnection-->bindService mIsBound: " + mIsBound);
}
3.啟動MessengerService幅聘,啟動消息循環(huán)
@Override
public void onCreate() {
super.onCreate();
LogUtils.i(Constants.TAG + " essengerService", "MessengerService -->onCreate");
mWorkThread = new WorkThread();
mWorkThread.start();
}
public class WorkThread extends Thread {
public ServiceHandler mHandler;
@Override
public void run() {
Looper.prepare();
LogUtils.i(Constants.TAG + " essengerService", "MessengerService -->new ServiceHandler");
//通過ServiceHandler來處理收到的消息
mHandler = new ServiceHandler();
Messenger mMessenger = new Messenger(mHandler);
// OkBus.getInstance().mServiceMessenger = mMessenger;
try {
resultRef.set(mMessenger);
} catch (Exception e) {
e.printStackTrace();
} finally {
latch.countDown();
}
Looper.loop();
}
public void quit() {
mHandler.getLooper().quit();
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
try {
latch.await(10, TimeUnit.SECONDS); //最多等待10秒
} catch (Exception e) { //等待中斷
e.printStackTrace();
}
Messenger mMessenger = resultRef.get();
return mMessenger.getBinder();
}
4.初始化OkBus并發(fā)送消息注冊
public void initModule(BaseModule mBaseModule, Messenger mServiceMessenger, int mModuleId, Messenger mClientMessenger) {
this.mServiceMessenger = mServiceMessenger;
this.mModuleId = mModuleId;
this.mBaseModule = mBaseModule;
isModule.set(true);
mBaseModule.isConnected.set(true);
//線程池獲取信息
Message msg = Message.obtain();
Bundle data = new Bundle();
data.putInt(Constants.REGISTER_ID, mModuleId);//注冊模塊信息
msg.setData(data);
msg.replyTo = mClientMessenger; //將處理消息的Messenger綁定到消息上帶到服務(wù)端
try {
//發(fā)送到MessengerService中處理
mServiceMessenger.send(msg);
} catch (Exception e) {
e.printStackTrace();
}
}
5.ServiceHandler中維護一個對Service Messenger到多個Client Messenger的關(guān)系
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
try {
Bundle bundle = msg.getData();
int registerId = bundle.getInt(Constants.REGISTER_ID, -1);
if (registerId > 0) {//注冊模塊類型的消息
LogUtils.logOnUI(Constants.TAG, "handleMessage: msg = [收到注冊模塊類型的消息]: registerId: " + Integer.toHexString(registerId));
//每個模塊對應(yīng)的ClientHandler
Messenger client = msg.replyTo;
mClientMessengers.put(registerId, client);//存儲Client端接受處理消息的Messenger來發(fā)送Message到Client
Message data = Message.obtain();
Bundle mBundle = new Bundle();
mBundle.putInt(Constants.REGISTER_RES, Constants.REGISTER_SEC); //通知Client模塊注冊成功
data.setData(mBundle);
try {
client.send(data); //回調(diào)注冊狀態(tài)給模塊
} catch (Exception e) {
e.printStackTrace();
}
}
6.介紹的模塊注冊結(jié)果
public class ClientHandler extends Handler {
@Override
public void handleMessage(Message msg) {
……
int resCode = bundle.getInt(Constants.REGISTER_RES, -1);
if (resCode < 0) {//收到普通消息
……
} else {//收到模塊注冊結(jié)果消息
boolean isRegisterSec = resCode == Constants.REGISTER_SEC;
if (isRegisterSec) {
LogUtils.logOnUI(Constants.TAG, "handleMessage() : reply = [注冊成功]");
}
}
}
}
7.其綁定完畢之后坷剧,將module信息注冊到OkBus,之后會使用afterConneted()來初始化想要接收的消息
public ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
LogUtils.logOnUI(Constants.TAG, "ServiceConnection-->onServiceConnected 已自動喚醒服務(wù)器");
Messenger mServiceMessenger = new Messenger(service);
OkBus.getInstance().initModule(mBaseModule, mServiceMessenger, getModuleId(), mWorkThread.clientHandler);
afterConnected();
}
8.通過ServiceBus來注冊其他module會跨module調(diào)用過來的消息喊暖。
@Override
public void afterConnected() {
ServiceBus.getInstance().registerService(Constants.SERVICE_A_UID, msg -> {
LogUtils.logOnUI(Constants.TAG, "afterConnected a 進程收到[服務(wù)請求]消息:ServiceMessage-->hello: " + Integer.toHexString(Math.abs(msg.what)));
return "10086";
});
}
9.服務(wù)注冊后惫企,可以看到其會通過onEvent返回回調(diào)的msg對象(CallBack接口)
/**
* 注冊服務(wù)
*
* @param serviceId 服務(wù)id
* @param callback 服務(wù)調(diào)用的回調(diào)
* @param <T> 服務(wù)返回的數(shù)據(jù)范型
*/
public <T> void registerService(final int serviceId, final CallBack<T> callback) {
LogUtils.logOnUI(Constants.TAG, "注冊服務(wù) " + Integer.toHexString(Math.abs(serviceId)));
okBus.unRegister(serviceId);//服務(wù)提供者只能有一個
okBus.register(serviceId, msg -> {
//TODO 優(yōu)化到子線程
okBus.onEvent(serviceId - 1, callback.onCall(msg));
});
}
到這里就介紹完初始化和注冊流程了。
接下來介紹一下消息發(fā)送的架構(gòu)陵叽,注意一下的模塊服務(wù)規(guī)則
//==================模塊間的服務(wù)定義============//
/**
* 服務(wù)定義規(guī)則:
* 1狞尔、服務(wù)的請求ID必須是負(fù)值(正值表示事件)
* 2、服務(wù)的請求ID必須是奇數(shù)巩掺,偶數(shù)表示該服務(wù)的返回事件偏序,
* 即: requestID-1 = returnID
* 例如 -0xa001表示服務(wù)請求 -0xa002表示-0xa001的服務(wù)返回
*/
public static final int SERVICE_A_UID = -0xa001;
/**
* 異步調(diào)用遠(yuǎn)端服務(wù)
*/
findViewById(R.id.bt_1).setOnClickListener(v -> {
//異步調(diào)用,
ServiceBus.getInstance().fetchService(Constants.SERVICE_A_UID, msg -> {
LogUtils.logOnUI(Constants.TAG, "b 進程收到[異步服務(wù)返回]消息: 獲取到的UID-->" + msg.obj);
Toast.makeText(BModuleActivity.this,
"b 進程收到[異步服務(wù)返回]消息: 獲取到的UID-->" + msg.obj,
Toast.LENGTH_SHORT).show();
});
});
具體步驟
1.對ID的請求限制
2.module連接的判斷胖替,沒有連接就嘗試連接
3.喚醒目標(biāo)進程
4.注冊回調(diào)
5.通知目標(biāo)模塊
/**
* 異步調(diào)用服務(wù)
*
* @param serviceId 服務(wù)id
* @param callback 回調(diào)
*/
public void fetchService(final int serviceId, final Event callback) {
if (serviceId > 0 || serviceId % 2 == 0) {
assert false : "請求ID必須是負(fù)奇值!";
return;
}
if (okBus.isModule() && !okBus.isModuleConnected()) {
LogUtils.logOnUI(Constants.TAG, "請求失敗研儒,服務(wù)已經(jīng)斷開鏈接豫缨,嘗試重新打開服務(wù),進行請求");
BaseAppModuleApp.getBaseApplication().connectService();
return;
}
//自動喚醒目標(biāo)進程
if (okBus.isModule()) {
String module_name = Integer.toHexString(Math.abs(serviceId)).substring(0, 1);
noticeModule(module_name, serviceId, null);
}
//1端朵、先注冊回調(diào)
okBus.register(serviceId - 1, msg -> {
callback.call(msg);
okBus.unRegister(serviceId - 1);//服務(wù)是單次調(diào)用好芭,觸發(fā)后即取消注冊
});
//2、通知目標(biāo)模塊
okBus.onEvent(serviceId);
}
喚醒目標(biāo)進程
/**
* 喚醒目標(biāo)進程
*
* @param module_name 模塊名
* @param serviceId 服務(wù)ID
* @param url 要打開的url
*/
public void noticeModule(String module_name, int serviceId, String url) {
Intent ait = new Intent(NoticeService.class.getCanonicalName());// 5.0+ need explicit intent //喚醒目標(biāo)進程的服務(wù)Action名
ait.setPackage(Constants.MODULE_PACKAGE_PRE + module_name); //喚醒目標(biāo)進程的包名
//綁定包名
BaseAppModuleApp.getBaseApplication().bindService(ait, new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
if (service != null) {
LogUtils.logOnUI(Constants.TAG, "已經(jīng)自動喚醒" + module_name);
Messenger moduleNameMessenger = new Messenger(service);
Message _msg = Message.obtain();
Bundle _data = new Bundle();
_data.putBoolean(Constants.NOTICE_MSG, true);
_msg.setData(_data);
_msg.replyTo = okBus.mServiceMessenger;//把服務(wù)器的信使給目標(biāo)組件的信使冲呢,讓他倆自己聯(lián)系舍败,這里僅僅是通知
try {
moduleNameMessenger.send(_msg);
} catch (Exception e) {
e.printStackTrace();
}
try {
Thread.sleep(200);//給服務(wù)器和目標(biāo)組件500ms聯(lián)系的時間
} catch (Exception e) {
e.printStackTrace();
}
} else {
LogUtils.logOnUI(Constants.TAG, module_name + "進程,本來就是醒的");
}
if (serviceId < 0) { //喚醒成功,繼續(xù)發(fā)送異步請求敬拓,通知目標(biāo)模塊
okBus.onEvent(serviceId);
}
if (!TextUtils.isEmpty(url)) { //目標(biāo)url不為空邻薯,繼續(xù)打開目標(biāo)
OkBus.getInstance().onEvent(Constants.ROUTER_OPEN_URL, url);
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
LogUtils.logOnUI(Constants.TAG, "自動喚醒目標(biāo)進程失敗 module_name:" + module_name);
}
}, BIND_AUTO_CREATE);
}
啟動模塊,并傳遞綁定對象
/**
* 收到喚醒通知之后乘凸,初始化模塊厕诡,并自動去服務(wù)器注冊
*
* @param intent
* @return
*/
@Nullable
@Override
public IBinder onBind(Intent intent) {
LogUtils.logOnUI(Constants.TAG, getPackageName() + " 收到喚醒通知");
//獲取模塊的module
BaseModule mBaseModule = BaseAppModuleApp.getBaseApplication().mBaseModule;
if (!mBaseModule.isConnected.get()) {
LogUtils.logOnUI(Constants.TAG, getPackageName() + " 我被喚醒啦");
//初始化module,啟動module的ClientHandler(Messenger)
mBaseModule.init(latch, resultRef);
mBaseModule.afterConnected();
try {
//超時限制
latch.await(2000, TimeUnit.SECONDS);
} catch (Exception e) { //等待中斷
e.printStackTrace();
}
}
//返回ClientHandler的Binder對象
return mBaseModule.mWorkThread.clientHandler.getBinder();
}
發(fā)送消息营勤,其最終是通過ServiceBus轉(zhuǎn)發(fā)到每個模塊OkBus灵嫌,然后Binder傳遞的Messenger關(guān)聯(lián)來完成信息傳遞。
/**
* @param tag 發(fā)送消息的事件ID
* @param data 發(fā)送消息的數(shù)據(jù)
* @return
*/
public OkBus onEvent(int tag, Object data) {
//發(fā)送時間冀偶,所以tag小于0
String hex = Integer.toHexString(Math.abs(tag));
LogUtils.i("Message OkBus", "onEvent " + (tag > 0 ? "[普通]" : "[服務(wù)]") + " tag: " + hex);
//1、本地先處理非服務(wù)消息
if (tag >= 0) onLocalEvent(tag, data);
//2渔嚷、如果是組建化进鸠,向服務(wù)器發(fā)消息
if (isModule.get()) {
//保證發(fā)送時服務(wù)啟動
if (!isModuleConnected()) {
LogUtils.i("Message OkBus", "發(fā)消息失敗,服務(wù)已經(jīng)斷開鏈接形病,嘗試重新打開服務(wù)客年,進行發(fā)消息");
BaseAppModuleApp.getBaseApplication().connectService();
return this;
}
//數(shù)據(jù)為空,即為事件
if (data == null || data instanceof Serializable) {
Message newMsg = new Message();
if (data != null) {
Bundle bundle = new Bundle();
bundle.putSerializable(Constants.MESSAGE_DATA, (Serializable) data);
newMsg.setData(bundle);
}
newMsg.arg1 = mModuleId;
newMsg.what = tag;
try {
//發(fā)送信息到目標(biāo)Service
mServiceMessenger.send(newMsg);
} catch (Exception e) {
e.printStackTrace();
}
} else {
assert false : "跨進程時漠吻,你傳遞的對象沒有序列化量瓜!";
}
} else if (tag < 0) {//非組件化時本地處理服務(wù)消息
onLocalEvent(tag, data);
}
return this;
}
使用Messenger通信框架設(shè)計就介紹到這里。
1.Modular框架途乃,模塊內(nèi)傳輸使用了OkBus的路由傳輸绍傲,而在跨模塊則使用Messenger的方式來完成
2.Messenger實際是一個封裝好的IBinder對象
3.Modular通過合理設(shè)置跨模塊的傳輸?shù)膮f(xié)議邏輯來完成信息傳輸