大家好,我系苍王。
以下是我这个系列的相关文章,有兴趣可以参考一下,可以给个喜欢或者关注我的文章。

[Android]如何做一个崩溃率少于千分之三噶应用app--章节列表

Android组件化架构热卖中

组件化群1已经满员,进来的可以加群2 763094035



上一节,介绍了使用AIDL的进程通信框架。
这一节给大家介绍Messenger的通信框架,而Messenger其意思是“信使”的意思
使用Messenger的优势在于
1.实际传递的是Message,可以复用信息池
2.支持信息回调
3.不需要编写aidl

Messenger通信原理图

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通过合理设置跨模块的传输的协议逻辑来完成信息传输

更多相关文章

  1. [置顶] Android(安卓)轻松实现仿QQ消息下拉刷新
  2. 深入讲解Android(安卓)MVP框架,附一个很屌的实现MVP架构的开源库T
  3. Android推送通知的实现--PHP+ANDROID做消息推送:基于IBM的MQTT协
  4. Android中的Message机制
  5. 史上最详细创建 Android(安卓)AIDL 远程服务步骤
  6. Android(安卓)Handler多线程详解
  7. [Android(安卓)基础] -- 深入理解 Android(安卓)Build 系统
  8. Android子线程中更新UI的3种方法
  9. Android(安卓)Handle的使用

随机推荐

  1. android DatePicker和TimePicke用法
  2. Android(安卓)Studio(Gradle)解决库依赖
  3. android UI menu code
  4. android Socket实现简单聊天小程序
  5. Android(安卓)Dialog 简单封装
  6. Android利用canvas画各种图形
  7. android 自定义LinearLayout
  8. Android(安卓)EditText 让编辑框只能输入
  9. Android应用开发相关下载资源
  10. android webview 自己跳转