文章目錄
- 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跨程序調用的流程圖。
圖 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;
}
}