在上次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对象进行缓存,以便之后不用每次都创建,提高性能。
由于篇幅已经比较长了,剩下手写的功能入到下篇,说实话代码量还是挺大的,但是这样写一遍对于自己技能的提升还是挺有帮助的。