zoukankan      html  css  js  c++  java
  • 跨进程架构HermesEventBus原理分析到手写实现<二>

    在上次https://www.cnblogs.com/webor2006/p/12186914.html对于HermesEventBus的核心原理了解了之后,接下来则准备从0开始手动来实现这样一个跨进程通信的功能,当然实现的代码不可能跟官方的一模一样,简化了很多,重点是效果是一样的,通过这样的手动的实现可以进一步加深对于这个框架的理解。

    定义AIDL文件:

    这里还是在之前那个工程上进行代码的编写,上次的分析中很明显跨进程的实现还得通过AIDL,所以首先先来定义好它。

    接下来则需要定义一个服务端的Service,如下:

    好,这里思考一个问题,对于平常我们写AIDL时对于每个数据其实都得要写一个AIDL文件,比如方法中涉及到多个对象,比如Student、Friend、Teacher...,每个都得对应一个独立的AIDL,很显然不是特别方便,在Hermes中则对它进行了一次封装,也就是只需要定义一次,之后我们在从客户端调用AIDL往服务端发时,不会再增加AIDL文件,比较通用,我们先来瞅一下Hermes的AIDL中的方法定义:

    这样的话,咱们只要定义三个AIDL既可,一个AIDL是方法的描述,另外两个AIDL则是方法中的入参及结果类型,下面咱们来定义一下:

    然后这里再定义对应的Request和Response的实体:

    有了这个实体对象之后,接下来则可以将其定义到对应的AIDL文件当中了:

     

    此时就可以定义AIDL的方法了:

    此时编译一下:

    这里有个注意点:

    init():

    接下来先定义一个单例对像,至于定义它了有啥用,在之后会领悟到的,没成形之前先看一下既可:

    然后得先初始化Hermes,如之前使用一样:

    所以建一个类:

    然后用咱们定义的这个初始化替换一下:

     

    register():

    这里咱们稍改一下,将我们写的单例UserManager注册进去:

    接下来咱们来实现一下这个register,先回看一下框架是如何实现的:

    最终是转由TypeCenter来实现注册细节,所以咱们也校仿一下:

    然后现在就得看一下在TypeCenter.register()的具体实现了,先看一下框架的实现,来校仿:

     所以,咱们也一样:

    好,接下来先实现注册类的方法,还是校仿着hermes来进行编写:

    其中mRawClasses定义为:

    好,照着实现一下:

    其中咱们使用了一个新的map的api,叫putIfAbsent(),而平常我们通常使用的是put(),那它俩有啥区别呢?

     秒懂了,接下来再来实现方法注册,还是先看一下Hermes框架的实现细节:

    那,咱们直接校仿下呗:

    其中这里拷了一个MyTypeUtils,其实就是Hermes框架中的:

    里面的getMethodId()的细节瞅一下:

    拿咱们注册的UserManager中的一个方法为例:

    其实上面的getMethodId最终生成的字符为setStudent(Student),这种方法描述在一个类中肯定是唯一的,所以可以当成key来用。那思考一下,为啥要将注册的这个类和它里面的方法给缓存起来呢?其实就是为了减少反射调用,从上一节对于Hermers的原理来看,最终发送端的进程是通过反射来调用到服务端的方法,所以缓存起来是能提高性能的,毕境反射是比较耗性能的嘛。

    connect():

    对于上一步注册的UserManager是干嘛用的呢?其实是供客户端来使用的,所以接下来得回到另一个子进程来连接一下主进程的服务开启AIDL的跨进程通讯了,如:

    ,这一步也是最核心的,把它写出来基本上对于Hermers框加的跨进程原理就理解得非常透了,下面回到SecondActivity开始实现和服务器的服务连接:

    接着还是看框架的实现,然后咱们来校仿一下:

     

    直接抄过来:

     

      

    此时就需要来绑定远程程序建立连接了,还是先看一下框架的实现,然后咱们基于上面的抄一下既可,重在理解:

    咱们精简地抄一下:

    public class ServiceConnectionManager {
        private static final ServiceConnectionManager ourInstance = new ServiceConnectionManager();
        //Class对应的链接对象
        private final ConcurrentHashMap<Class<? extends HermesService>, HermesServiceConnection> mHermesServiceConnections = new ConcurrentHashMap<Class<? extends HermesService>, HermesServiceConnection>();
        //    Class  对应的Binder  对象
        private final ConcurrentHashMap<Class<? extends HermesService>, MyEventBusService> mHermesServices =
                new ConcurrentHashMap<Class<? extends HermesService>, MyEventBusService>();
    
        public static ServiceConnectionManager getInstance() {
            return ourInstance;
        }
    
        private ServiceConnectionManager() {
        }
    
        public void bind(Context context, String packageName, Class<? extends HermesService> service) {
            HermesServiceConnection connection = new HermesServiceConnection(service);
            mHermesServiceConnections.put(service, connection);
            Intent intent;
            if (TextUtils.isEmpty(packageName)) {
                intent = new Intent(context, service);
            } else {
                intent = new Intent();
                intent.setClassName(packageName, service.getName());
            }
            context.bindService(intent, connection, Context.BIND_AUTO_CREATE);
        }
    
        //     接受远端的binder 对象   进程B就可以了通过Binder对象去操作 服务端的 方法
        private class HermesServiceConnection implements ServiceConnection {
            private Class<? extends HermesService> mClass;
    
            HermesServiceConnection(Class<? extends HermesService> service) {
                mClass = service;
            }
    
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                MyEventBusService hermesService = MyEventBusService.Stub.asInterface(service);
                mHermesServices.put(mClass, hermesService);
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
                mHermesServices.remove(mClass);
            }
        }
    }

    上面将连接和Binder对象进行缓存,以便之后不用每次都创建,提高性能。

    由于篇幅已经比较长了,剩下手写的功能入到下篇,说实话代码量还是挺大的,但是这样写一遍对于自己技能的提升还是挺有帮助的。

  • 相关阅读:
    双网卡主机无法管理的故障
    hosts文件导致无法访问网站
    获取webshell的十种方法
    XSS跨站攻击
    Ubuntu 使用中的问题总结
    ubuntu linux 13.04更新
    mysql root密码重置
    防火墙工作模式简介
    SE 2014年4月30日
    SE 2014年4月29日
  • 原文地址:https://www.cnblogs.com/webor2006/p/12196171.html
Copyright © 2011-2022 走看看