文章目录
- 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;
@Override
public void onCreate() {
super.onCreate();
Log.d("hongxue", "onCreate " + (i++));
}
}
<activity android:name=".SecondActivity"
android:process=":s"/>
输出结果:
hongxue: onCreate 0
hongxue: onCreate 0
i的值并没有增加,说明不同进程间内存不会共享。
首先给出hermes跨进程调用的流程图。
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHL0cGRPRTVXRGNk1mY2hmMMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZwpmLwATM5UDOwkDM3AzNwkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
图 hermes跨进程调用
- 服务端和客户端都会存在一个单例,根据开始的小实验我们知道,不同的进程间内存不共享,所以客户端的是一个单例的动态代理。
- 在跨进程通信中,如果存在多条数据的发送,就要创建多个aidl文件。为了防止这种情况,hermes对数据进行了再次封装,通过json将对象转化成字符串。
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 {
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
并在Manifest文件中添加:
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>() {
@Override
public Request createFromParcel(Parcel in) {
return new Request(in);
}
@Override
public Request[] newArray(int size) {
return new Request[size];
}
};
@Override
public int describeContents() {
return 0;
}
// 序列化
@Override
public 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>() {
@Override
public Responce createFromParcel(Parcel in) {
return new Responce(in);
}
@Override
public Responce[] newArray(int size) {
return new Responce[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public 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;
}
@Override
public 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);
}
//缓存class
private 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;
}
}