跨进程架构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对象进行缓存,以便之后不用每次都创建,提高性能。

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

posted on 2020-01-15 13:25  cexo  阅读(782)  评论(0编辑  收藏  举报

导航