[Android]你不知道的Android进程化(5)--进程通信Messenger框架
大家好,我系苍王。
以下是我这个系列的相关文章,有兴趣可以参考一下,可以给个喜欢或者关注我的文章。
[Android]如何做一个崩溃率少于千分之三噶应用app--章节列表
Android组件化架构热卖中组件化群1已经满员,进来的可以加群2 763094035
上一节,介绍了使用AIDL的进程通信框架。
这一节给大家介绍Messenger的通信框架,而Messenger其意思是“信使”的意思
使用Messenger的优势在于
1.实际传递的是Message,可以复用信息池
2.支持信息回调
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当中存在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实现对象是MessengerImpl
final IMessenger getIMessenger() { synchronized (mQueue) { if (mMessenger != null) { return mMessenger; } mMessenger = new MessengerImpl(); return mMessenger; } }
这里IMessenger是调用Handler的send方法来发送消息的。
private final class MessengerImpl extends IMessenger.Stub { public void send(Message msg) { msg.sendingUid = Binder.getCallingUid(); Handler.this.sendMessage(msg); } }
每个Message当中也包含了一个replyTo的变量用户回调
/** * 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独立的实现了Parcelable和使用aidl的通信方式
接下来我们介绍一下Modular框架是用Messenger通信设计。
不同于上一节介绍的ModularArchitecture的aidl中通信是1对1的通信,Modular提供的通信框架是通过1对多的发送方式来传递的。
以下是Messenger的注册流程图
Messenger注册流程图
1.每个模块初始化时启动一个消息队列来监听消息。
@Override public void init() { mBaseModule = this; //启动线程接收消息 mWorkThread = new WorkThread(); mWorkThread.start(); //注册跳转路由 OkBus.getInstance().register(Constants.ROUTER_OPEN_URL, new Event() { @Override public void call(Message msg) { String url = (String) msg.obj; //实际跳转使用的Router Router.openLocalUrl(BaseAppModuleApp.getBaseApplication(), url); } }, Bus.UI); //线程参数 } 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
/** * 连接服务器 */ 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,启动消息循环
@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并发送消息注册
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绑定到消息上带到服务端 try { //发送到MessengerService中处理 mServiceMessenger.send(msg); } catch (Exception e) { e.printStackTrace(); } }
5.ServiceHandler中维护一个对Service Messenger到多个Client Messenger的关系
@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)); //每个模块对应的ClientHandler Messenger client = msg.replyTo; mClientMessengers.put(registerId, client);//存储Client端接受处理消息的Messenger来发送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); //回调注册状态给模块 } catch (Exception e) { e.printStackTrace(); } }
6.介绍的模块注册结果
public class ClientHandler extends Handler { @Override public void handleMessage(Message msg) { …… int resCode = bundle.getInt(Constants.REGISTER_RES, -1); if (resCode < 0) {//收到普通消息 …… } else {//收到模块注册结果消息 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 已自动唤醒服务器"); Messenger mServiceMessenger = new Messenger(service); OkBus.getInstance().initModule(mBaseModule, mServiceMessenger, getModuleId(), mWorkThread.clientHandler); afterConnected(); }
8.通过ServiceBus来注册其他module会跨module调用过来的消息。
@Override public void afterConnected() { ServiceBus.getInstance().registerService(Constants.SERVICE_A_UID, msg -> { LogUtils.logOnUI(Constants.TAG, "afterConnected a 进程收到[服务请求]消息:ServiceMessage-->hello: " + Integer.toHexString(Math.abs(msg.what))); return "10086"; }); }
9.服务注册后,可以看到其会通过onEvent返回回调的msg对象(CallBack接口)
/** * 注册服务 * * @param serviceId 服务id * @param callback 服务调用的回调 * @param 服务返回的数据范型 */ public void registerService(final int serviceId, final CallBack callback) { LogUtils.logOnUI(Constants.TAG, "注册服务 " + Integer.toHexString(Math.abs(serviceId))); okBus.unRegister(serviceId);//服务提供者只能有一个 okBus.register(serviceId, msg -> { //TODO 优化到子线程 okBus.onEvent(serviceId - 1, callback.onCall(msg)); }); }
到这里就介绍完初始化和注册流程了。
接下来介绍一下消息发送的架构,注意一下的模块服务规则
//==================模块间的服务定义============// /** * 服务定义规则: * 1、服务的请求ID必须是负值(正值表示事件) * 2、服务的请求ID必须是奇数,偶数表示该服务的返回事件, * 即: requestID-1 = returnID * 例如 -0xa001表示服务请求 -0xa002表示-0xa001的服务返回 */ public static final int SERVICE_A_UID = -0xa001; /** * 异步调用远端服务 */ findViewById(R.id.bt_1).setOnClickListener(v -> { //异步调用, ServiceBus.getInstance().fetchService(Constants.SERVICE_A_UID, msg -> { LogUtils.logOnUI(Constants.TAG, "b 进程收到[异步服务返回]消息: 获取到的UID-->" + msg.obj); Toast.makeText(BModuleActivity.this, "b 进程收到[异步服务返回]消息: 获取到的UID-->" + msg.obj, Toast.LENGTH_SHORT).show(); }); });
具体步骤
1.对ID的请求限制
2.module连接的判断,没有连接就尝试连接
3.唤醒目标进程
4.注册回调
5.通知目标模块
/** * 异步调用服务 * * @param serviceId 服务id * @param callback 回调 */ public void fetchService(final int serviceId, final Event callback) { if (serviceId > 0 || serviceId % 2 == 0) { assert false : "请求ID必须是负奇值!"; return; } if (okBus.isModule() && !okBus.isModuleConnected()) { LogUtils.logOnUI(Constants.TAG, "请求失败,服务已经断开链接,尝试重新打开服务,进行请求"); BaseAppModuleApp.getBaseApplication().connectService(); return; } //自动唤醒目标进程 if (okBus.isModule()) { String module_name = Integer.toHexString(Math.abs(serviceId)).substring(0, 1); noticeModule(module_name, serviceId, null); } //1、先注册回调 okBus.register(serviceId - 1, msg -> { callback.call(msg); okBus.unRegister(serviceId - 1);//服务是单次调用,触发后即取消注册 }); //2、通知目标模块 okBus.onEvent(serviceId); }
唤醒目标进程
/** * 唤醒目标进程 * * @param module_name 模块名 * @param serviceId 服务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 //唤醒目标进程的服务Action名 ait.setPackage(Constants.MODULE_PACKAGE_PRE + module_name); //唤醒目标进程的包名 //绑定包名 BaseAppModuleApp.getBaseApplication().bindService(ait, new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { if (service != null) { LogUtils.logOnUI(Constants.TAG, "已经自动唤醒" + 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;//把服务器的信使给目标组件的信使,让他俩自己联系,这里仅仅是通知 try { moduleNameMessenger.send(_msg); } catch (Exception e) { e.printStackTrace(); } try { Thread.sleep(200);//给服务器和目标组件500ms联系的时间 } catch (Exception e) { e.printStackTrace(); } } else { LogUtils.logOnUI(Constants.TAG, module_name + "进程,本来就是醒的"); } if (serviceId < 0) { //唤醒成功,继续发送异步请求,通知目标模块 okBus.onEvent(serviceId); } if (!TextUtils.isEmpty(url)) { //目标url不为空,继续打开目标 OkBus.getInstance().onEvent(Constants.ROUTER_OPEN_URL, url); } } @Override public void onServiceDisconnected(ComponentName name) { LogUtils.logOnUI(Constants.TAG, "自动唤醒目标进程失败 module_name:" + module_name); } }, BIND_AUTO_CREATE); }
启动模块,并传递绑定对象
/** * 收到唤醒通知之后,初始化模块,并自动去服务器注册 * * @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(); }
发送消息,其最终是通过ServiceBus转发到每个模块OkBus,然后Binder传递的Messenger关联来完成信息传递。
/** * @param tag 发送消息的事件ID * @param data 发送消息的数据 * @return */ public OkBus onEvent(int tag, Object data) { //发送时间,所以tag小于0 String hex = Integer.toHexString(Math.abs(tag)); LogUtils.i("Message OkBus", "onEvent " + (tag > 0 ? "[普通]" : "[服务]") + " tag: " + hex); //1、本地先处理非服务消息 if (tag >= 0) onLocalEvent(tag, data); //2、如果是组建化,向服务器发消息 if (isModule.get()) { //保证发送时服务启动 if (!isModuleConnected()) { LogUtils.i("Message OkBus", "发消息失败,服务已经断开链接,尝试重新打开服务,进行发消息"); BaseAppModuleApp.getBaseApplication().connectService(); return this; } //数据为空,即为事件 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 { //发送信息到目标Service mServiceMessenger.send(newMsg); } catch (Exception e) { e.printStackTrace(); } } else { assert false : "跨进程时,你传递的对象没有序列化!"; } } else if (tag < 0) {//非组件化时本地处理服务消息 onLocalEvent(tag, data); } return this; }
使用Messenger通信框架设计就介绍到这里。
1.Modular框架,模块内传输使用了OkBus的路由传输,而在跨模块则使用Messenger的方式来完成
2.Messenger实际是一个封装好的IBinder对象
3.Modular通过合理设置跨模块的传输的协议逻辑来完成信息传输
更多相关文章
- [置顶] Android(安卓)轻松实现仿QQ消息下拉刷新
- 深入讲解Android(安卓)MVP框架,附一个很屌的实现MVP架构的开源库T
- Android推送通知的实现--PHP+ANDROID做消息推送:基于IBM的MQTT协
- Android中的Message机制
- 史上最详细创建 Android(安卓)AIDL 远程服务步骤
- Android(安卓)Handler多线程详解
- [Android(安卓)基础] -- 深入理解 Android(安卓)Build 系统
- Android子线程中更新UI的3种方法
- Android(安卓)Handle的使用