美文网首页KotlinAndroid开发经验谈Android开发
[Android]你不知道的Android进程化(5)--进程通

[Android]你不知道的Android进程化(5)--进程通

作者: CangWang | 来源:发表于2018-04-16 08:55 被阅读573次

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

    [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 <T>       服务返回的数据范型
         */
        public <T> void registerService(final int serviceId, final CallBack<T> 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通过合理设置跨模块的传输的协议逻辑来完成信息传输

    相关文章

      网友评论

      • 一个大西瓜CPI:Android组件化构架书籍里面的代码资源能不能贴出来?
        CangWang:@一个大西瓜CPI 源码都在每页的页尾

      本文标题:[Android]你不知道的Android进程化(5)--进程通

      本文链接:https://www.haomeiwen.com/subject/uzjgcftx.html