文章目录

  • 1 注册实现
    • 1.1 创建aidl文件
    • 1.2 服务端实现
      • 1.2.1 HermesService
      • 1.2.2 创建Request和Responce
      • 1.2.3 创建单例UserManager.java
      • 1.2.4 创建数据类Friend.java
      • 1.2.5 创建Hermes.java

参考:
https://blog.csdn.net/xiaofei_it/article/details/51464518
https://github.com/Xiaofei-it/Hermes
https://www.jianshu.com/p/29999c1a93cd


链接:
饿了么开源项目Hermes跨进程架构分析1-服务端注册
饿了么开源项目Hermes跨进程架构分析2-客户端连接


先做一个小实验,SecondActivity另启一个进程,代码如下:

public class MyApplication extends Application {private static int i= 0;@Overridepublic void onCreate() {super.onCreate();Log.d("hongxue", "onCreate " + (i++));}}
        <activity android:name=".SecondActivity"android:process=":s"/>

输出结果:

hongxue: onCreate 0
hongxue: onCreate 0

i的值并没有增加,说明不同进程间内存不会共享。


首先给出hermes跨进程调用的流程图。

图 hermes跨进程调用

  1. 服务端和客户端都会存在一个单例,根据开始的小实验我们知道,不同的进程间内存不共享,所以客户端的是一个单例的动态代理。

  2. 在跨进程通信中,如果存在多条数据的发送,就要创建多个aidl文件。为了防止这种情况,hermes对数据进行了再次封装,通过json将对象转化成字符串。

3个步骤:

  1. 服务端注册
  2. 客户端连接
  3. 通信

1 注册实现

1.1 创建aidl文件

先创建aidl文件用于实现进程间通信:

1 MyEventBusService.aidl

import com.hongx.hermes.Request;
import com.hongx.hermes.Responce;
interface MyEventBusService {Responce send(in Request request);
}

2 Responce.aidl

package com.hongx.hermes;
parcelable Responce;

3 Request.aidl

package com.hongx.hermes;
parcelable Request;

1.2 服务端实现

1.2.1 HermesService

需要创建一个 Service 供客户端远程绑定,这里命名为 HermesService。

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;public class HermesService extends Service {@Overridepublic IBinder onBind(Intent intent) {return null;}
}

并在Manifest文件中添加:

 <service android:name=".service.HermesService" />

1.2.2 创建Request和Responce

创建Request.java:

import android.os.Parcel;
import android.os.Parcelable;public class Request implements Parcelable {//请求的对象  RequestBean 对应的json字符串private String data;//    请求对象的类型private int type;//    反序列化   A进程protected Request(Parcel in) {data = in.readString();type=in.readInt();}public String getData() {return data;}public int getType() {return type;}public Request(String data, int type) {this.data = data;this.type = type;}public static final Creator<Request> CREATOR = new Creator<Request>() {@Overridepublic Request createFromParcel(Parcel in) {return new Request(in);}@Overridepublic Request[] newArray(int size) {return new Request[size];}};@Overridepublic int describeContents() {return 0;}//  序列化@Overridepublic void writeToParcel(Parcel parcel, int i) {parcel.writeString(data);parcel.writeInt(type);}
}

创建Responce.java:

import android.os.Parcel;
import android.os.Parcelable;public class Responce implements Parcelable {//    响应的对象private String data;public String getData() {return data;}protected Responce(Parcel in) {data = in.readString();}public Responce(String data) {this.data = data;}public static final Creator<Responce> CREATOR = new Creator<Responce>() {@Overridepublic Responce createFromParcel(Parcel in) {return new Responce(in);}@Overridepublic Responce[] newArray(int size) {return new Responce[size];}};@Overridepublic int describeContents() {return 0;}@Overridepublic void writeToParcel(Parcel parcel, int i) {parcel.writeString(data);}
}

注意:要先创建Responce.aidl和Request.aidl ,然后再创建Responce.java 和 Request.java,否则会报错。

1.2.3 创建单例UserManager.java

创建UserManager并注册到服务端,客户端就可以到服务端拿到代理对象。

public class UserManager implements IUserManager {Friend friend;private static UserManager sInstance = null;private UserManager() {}public static synchronized UserManager getInstance(){if(sInstance == null){sInstance = new UserManager();}return sInstance;}public static synchronized UserManager getInstance(String s){if(sInstance == null){sInstance = new UserManager();}return sInstance;}public Friend getFriend() {return friend;}public void setFriend(Friend friend) {this.friend = friend;}public static UserManager getsInstance() {return sInstance;}public static void setsInstance(UserManager sInstance) {UserManager.sInstance = sInstance;}
}

1.2.4 创建数据类Friend.java

public class Friend {private String name;private int age;public Friend(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Friend{" +"name='" + name + '\'' +", age=" + age +'}';}
}
public interface IUserManager {public Friend getFriend();public void setFriend(Friend friend);
}

1.2.5 创建Hermes.java

在MainActivity的onCreate方法中进行初始化和注册

  Hermes.getDefault().init(this);Hermes.getDefault().register(UserManager.class);

Hermes.java

public class Hermes {private Context mContext;private TypeCenter typeCenter;private ServiceConnectionManager serviceConnectionManager;private Gson gson = new Gson();//得到对象public static final int TYPE_NEW = 0;//得到单例public static final int TYPE_GET = 1;private static final Hermes ourInstance = new Hermes();public Hermes() {serviceConnectionManager = ServiceConnectionManager.getInstance();typeCenter = TypeCenter.getInstance();}public static Hermes getDefault() {return ourInstance;}public void init(Context context) {this.mContext = context.getApplicationContext();}//----------------------------服务端-------------------------public void register(Class<UserManager> clazz) {typeCenter.register(clazz);}//----------------------------客户端-------------------------public void connect(Context context,Class<HermesService> hermesServiceClass) {connectApp(context, null, hermesServiceClass);}private void connectApp(Context context, String packageName, Class<HermesService> hermesServiceClass) {init(context);serviceConnectionManager.bind(context.getApplicationContext(), packageName, hermesServiceClass);}public <T> T getInstance(Class<T> tClass, Object... parameters) {Responce responce = sendRequest(HermesService.class, tClass, null, parameters);return getProxy(HermesService.class, tClass);}private <T> T getProxy(Class<HermesService> hermesServiceClass, Class<T> tClass) {ClassLoader classLoader = hermesServiceClass.getClassLoader();T proxy = (T) Proxy.newProxyInstance(classLoader, new Class<?>[]{tClass},new HermesInvocationHander(hermesServiceClass, tClass));return proxy;}private <T> Responce sendRequest(Class<HermesService> hermesServiceClass,Class<T> tClass, Method method, Object[] parameters) {RequestBean requestBean = new RequestBean();//set全类名String className = null;if (tClass.getAnnotation(ClassId.class) == null) {requestBean.setClassName(tClass.getName());requestBean.setResultClassName(tClass.getName());} else {requestBean.setClassName(tClass.getAnnotation(ClassId.class).value());requestBean.setResultClassName(tClass.getAnnotation(ClassId.class).value());}//set方法if (method != null) {requestBean.setMethodName(TypeUtils.getMethodId(method));}//set参数RequestParameter[] requestParameters = null;if (parameters != null && parameters.length > 0) {requestParameters = new RequestParameter[parameters.length];for (int i = 0; i < parameters.length; i++) {Object parameter = parameters[i];String parameterClassName = parameter.getClass().getName();String parameterValue = gson.toJson(parameter);RequestParameter requestParameter = new RequestParameter(parameterClassName, parameterValue);requestParameters[i] = requestParameter;}}if (requestParameters != null) {requestBean.setRequestParameter(requestParameters);}Request request = new Request(gson.toJson(requestBean), TYPE_GET);return serviceConnectionManager.request(hermesServiceClass, request);}public <T> Responce sendObjectRequest(Class hermeService, Class<T> aClass,Method method, Object[] args) {RequestBean requestBean = new RequestBean();//set全类名String className = null;if (aClass.getAnnotation(ClassId.class) == null) {requestBean.setClassName(aClass.getName());requestBean.setResultClassName(aClass.getName());} else {requestBean.setClassName(aClass.getAnnotation(ClassId.class).value());requestBean.setResultClassName(aClass.getAnnotation(ClassId.class).value());}//set方法if (method != null) {requestBean.setMethodName(TypeUtils.getMethodId(method));}//set参数RequestParameter[] requestParameters = null;if (args != null && args.length > 0) {requestParameters = new RequestParameter[args.length];for (int i = 0; i < args.length; i++) {Object parameter = args[i];String parameterClassName = parameter.getClass().getName();String parameterValue = gson.toJson(parameter);RequestParameter requestParameter = new RequestParameter(parameterClassName, parameterValue);requestParameters[i] = requestParameter;}}if (requestParameters != null) {requestBean.setRequestParameter(requestParameters);}Request request = new Request(gson.toJson(requestBean), TYPE_NEW);return serviceConnectionManager.request(hermeService, request);}
}

Hermes中定义了初始化、注册等一系列方法,现在我们先看init和register方法,调用Hermes的register方法,最终调用的是TypeCenter的register方法,将UserManager对象保存在一个Map对象中。

TypeCenter.java

public class TypeCenter {//为了减少反射,所以保存起来private final ConcurrentHashMap<Class<?>, ConcurrentHashMap<String, Method>> mRawMethods;private final ConcurrentHashMap<String, Class<?>> mClazz;private static final TypeCenter ourInstance = new TypeCenter();public TypeCenter() {mRawMethods = new ConcurrentHashMap<Class<?>, ConcurrentHashMap<String, Method>>();mClazz = new ConcurrentHashMap<>();}public static TypeCenter getInstance() {return ourInstance;}public void register(Class<HxUserManager> clazz) {//注册--》类, 注册--》方法registerClass(clazz);registerMethod(clazz);}//缓存classprivate void registerClass(Class<HxUserManager> clazz) {String name = clazz.getName();mClazz.putIfAbsent(name, clazz);}private void registerMethod(Class<HxUserManager> clazz) {Method[] methods = clazz.getMethods();for (Method method : methods) {mRawMethods.putIfAbsent(clazz, new ConcurrentHashMap<String, Method>());ConcurrentHashMap<String, Method> map = mRawMethods.get(clazz);String methodId = TypeUtils.getMethodId(method);map.put(methodId, method);}}public Class<?> getClassType(String name) {if (TextUtils.isEmpty(name)) {return null;}Class<?> clazz = mClazz.get(name);if (clazz == null) {try {clazz = Class.forName(name);} catch (ClassNotFoundException e) {e.printStackTrace();}}return clazz;}public Method getMethod(Class<?> aClass, RequestBean requestBean) {String methodName = requestBean.getMethodName();//setFriend()if (methodName != null) {mRawMethods.putIfAbsent(aClass, new ConcurrentHashMap<String, Method>());ConcurrentHashMap<String, Method> methods = mRawMethods.get(aClass);Method method = methods.get(methodName);if(method != null){return method;}int pos = methodName.indexOf('(');Class[] paramters = null;RequestParameter[] requestParameters = requestBean.getRequestParameter();if (requestParameters != null && requestParameters.length > 0) {paramters = new Class[requestParameters.length];for (int i=0;i<requestParameters.length;i++) {paramters[i]=getClassType(requestParameters[i].getParameterClassName());}}method = TypeUtils.getMethod(aClass, methodName.substring(0, pos), paramters);methods.put(methodName, method);return method;}return null;}
}

饿了么开源项目Hermes跨进程架构分析1-服务端注册相关推荐

  1. 饿了么开源项目Hermes跨进程架构分析2-客户端连接

    饿了么开源项目Hermes跨进程架构分析1-服务端注册 饿了么开源项目Hermes跨进程架构分析2-客户端连接 文章目录 2客户端连接 2.1 SecondActivity 2.2 Hermes 2. ...

  2. 即时通讯(IM)开源项目OpenIM本周版本发布- v1.0.7-web端一键部署

    介绍 OpenIM:由前微信技术专家打造的基于 Go 实现的即时通讯(IM)开源项目,包括IM服务端和客户端SDK.开发者私有化部署,基于SDK二次开发,可以轻松替代第三方IM云服务,打造具备聊天.社 ...

  3. 学习 ET(1)- 开源的游戏客户端(基于 unity3d)服务端双端框架

    我: 客户端程序员,15+ 以上 C++ 编码经历, 还算扎实.Unity 编码经历 1年,C# 没有单独学过.真不想离开C++的世界,大形势驱使进入了Unity+C#世界. ET - 开源的游戏客户 ...

  4. 跨进程访问(AIDL服务)

    我们都知道Service的主要的作用是后台运行和跨进程访问. 关于Service后台运行请查看鄙人的另外一篇文章Service基础 本篇博文主要探讨的是跨进程访问~ 什么是AIDL Android系统 ...

  5. IEC61499开源项目FORTE部分源码分析

    一.IEC 61499简介 IEC 61499 作为工业自动化领域分布式控制系统级建模语言的标准,其第一(体系结构).二(软件工具要求).四(兼容文件的规则)部分的第一版于 2005 年正式发布,并在 ...

  6. Unity开源项目2D流体渲染实现分析

    开源项目LiquidEffect渲染分析 项目传送门 实现流程 步骤一 创建刚体 步骤二 降采样与模糊处理 降采样分析 C#部分 顶点着色器 片元着色器 分析 模糊分析 步骤三 Alpha过滤 项目传 ...

  7. 基于eBPF技术的开源项目Kindling之探针架构介绍

    Kindling开源项目是一款基于eBPF技术的云原生可观测性项目.本文将主要介绍探针的具体架构设计. Kindling探针的架构设计理念 Kindling架构设计中有一个很重要的理念:关注点分离(S ...

  8. vue.js+koa2项目实战(四)搭建koa2服务端

    搭建koa2服务端 安装两个版本的koa 一.版本安装 1.安装 koa1 npm install koa -g 注:必须安装到全局 2.安装 koa2 npm install koa@2 -g 二. ...

  9. mysql第五章项目二_Todo List:Node+Express 搭建服务端毗邻Mysql – 第五章(第1节)

    点击右上方红色按钮关注"web秀",让你真正秀起来 前言 万丈高楼平地起,我们的Todo List项目也是越来越结实了.Todo List的前面4章内容都是在为Client端开发, ...

最新文章

  1. 开源仓库Harbor搭建及配置过程
  2. 简单计算机病毒黑屏,教大家一个黑屏小程序
  3. 下列关于linux的进程,描述不正确的是,进程是资源管理的最小单位,2012年7月成人自考网络操作系统考试真题...
  4. 【团队管理】改造团队成员?
  5. VC ADO连接ACCESS步骤及错误处理
  6. C#经典名著:《C#入门经典》(第4版)
  7. 关于NSArray使用时用strong修饰还是copy修饰问题测试
  8. init进程 解析Android启动脚本init.rc 修改它使不启动android init.rc中启动一个sh文件...
  9. 无法直接打开jar文件,提示“你要以何种方式打开.jar文件”(已解决)
  10. SQLServer 数据库无法重命名
  11. 金仓数据库在 TPCE(dbt5,tpsE)测试框架方面的实践和突破
  12. asp.net摄影网站系统VS开发sqlserver数据库web结构c#编程计算机网页源码项目
  13. 操作系统简史(1)东方会有新的操作系统诞生吗?让历史告诉未来
  14. 第十四届蓝桥杯模拟赛(Python)
  15. 【Android】使用MediaExtractor、MediaMuxer去掉视频文件中的音频数据
  16. 手抛飞机大改装(4种机型,7种改法)干货!!
  17. 关于scene understanding场景理解概念的理解
  18. 王者农药新模式——智慧王者 树形递归
  19. 安排,全栈分布式微服务媒资管理系统(视频、代码)
  20. POJ3014(最小覆盖点;匈牙利算法)

热门文章

  1. 小米OPPO适配鸿蒙系统,以后oppo或者vivo以及小米有没有机会用使用华为鸿蒙系统?...
  2. i5 10400F和i5 10600K哪个性价比高
  3. 树莓派(raspbian)如何消除屏幕右上角“闪电”符号
  4. html+css实现横向时间线
  5. kolla安装(1)
  6. 概率论与数理统计 浙江大学 第44-53讲单元测验
  7. jquery实现ajax异步请求
  8. goland如何修改背景为图片
  9. python实现一个个人名片复杂一点,给出制作思路,使用面向对象的方法
  10. 易语言反截图_[搬运]反截图技术的原理及简单实现