作者:享学课堂终身VIP周周
简书ID:波澜步惊
转载请声明出处!
上一期《手把手讲解IPC框架》享学课堂周周同学分享了概念QA以及前置技能、传统方式IPC通信写法与使用IPC框架进行RPC通信的对比以及Demo展示三个部分。这一期他将继续为大家带来手把手讲解IPC框架分享。
正文大纲
一、概念QA以及前置技能
二、传统方式IPC通信写法与使用IPC框架进行RPC通信的对比
三、Demo展示
四、框架核心思想讲解
五、写在最后的话
接上一篇:明星学员作品:手把手讲解IPC框架(1)
四、框架核心思想讲解
我们不使用IPC框架时,有两件事非常恶心:
1. 随着业务的扩展,我们需要频繁(因为要新增业务接口)改动
AIDL
文件,而且AIDL
修改起来没有任何代码提示,只有到了编译之后,编译器才会告诉我哪里错了,而且 直接引用到的JavaBean
还必须手动再声明一次。实在是不想在这个上面浪费时间。2. 所有客户端
Activity
,只要想进行进程间binder
通信,就不可避免要去手动bindService
,随后去处理Binder
连接,重写ServiceConnection
,还要在适当的时候释放连接,这种业务不相关而且重复性很大的代码,要尽量少写。
IPC框架将会着重解决这两个问题。下面开始讲解核心设计思想
注:1.搭建框架牵涉的知识面会很广,我不能每个细节都讲得很细致,一些基础部分一笔带过的,如有疑问,希望能留言讨论。
2.设计思路都是环环相扣的,阅读时最好是从上往下依次理解.
框架思想四部曲:
1)业务注册
上文说到,直接使用
AIDL
通信,当业务扩展时,我们需要对AIDL
文件进行改动,而改起来比较费劲,且容易出错。怎么办?利用业务注册
的方式,将业务类
的class
对象,保存到服务端 内存中。进入Demo代码Registry.java
:
public class Ipc {
/**
* @param business
*/
public static void register(Class<?> business) {
//注册是一个单独过程,所以单独提取出来,放在一个类里面去
Registry.getInstance().register(business);
//注册机是一个单例,启动服务端,
// 就会存在一个注册机对象,唯一,不会随着服务的绑定解绑而受影响
}
...省略无关代码
}
/**
* 业务注册机
*/
public class Registry {
...省略不关键代码
/**
* 业务表
*/
private ConcurrentHashMap<String, Class<?>> mBusinessMap
= new ConcurrentHashMap<>();
/**
* 业务方法表, 二维map,key为serviceId字符串值,value为 一个方法map - key,方法名;value
*/
private ConcurrentHashMap<String, ConcurrentHashMap<String, Method>> mMethodMap
= new ConcurrentHashMap<>();
/**
* 业务类的实例,要反射执行方法,如果不是静态方法的话,还是需要一个实例的,所以在这里把实例也保存起来
*/
private ConcurrentHashMap<String, Object> mObjectMap = new ConcurrentHashMap<>();
/**
* 业务注册
* 将业务class的class和method对象都保存起来,以便后面反射执行需要的method
*/
public void register(Class<?> business) {
//这里有个设计,使用注解,标记所使用的业务类是属于哪一个业务ID,在本类中,ID唯一
ServiceId serviceId = business.getAnnotation(ServiceId.class);
//获取那个类头上的注解
if (serviceId == null) {
throw new RuntimeException("业务类必须使用ServiceId注解");
}
String value = serviceId.value();
mBusinessMap.put(value, business);
//把业务类的class对象用 value作为key,保存到map中
//然后要保存这个business类的所有method对象
ConcurrentHashMap<String, Method> tempMethodMap = mMethodMap.get(value);
//先看看方法表中是否已经存在整个业务对应的方法表
if (tempMethodMap == null) {
tempMethodMap = new ConcurrentHashMap<>();
//不存在,则new
mMethodMap.put(value, tempMethodMap);
// 并且将它存进去
}
for (Method method : business.getMethods()) {
String methodName = method.getName();
Class<?>[] parameterTypes = method.getParameterTypes();
String methodMapKey = getMethodMapKeyWithClzArr(methodName, parameterTypes);
tempMethodMap.put(methodMapKey, method);
}
...省略不关键代码
}
...省略不关键代码
/**
* 如何寻找到一个Method?
* 参照上面的构建过程,
*
* @param serviceId
* @param methodName
* @param paras
* @return
*/
public Method findMethod(String serviceId, String methodName, Object[] paras) {
ConcurrentHashMap<String, Method> map = mMethodMap.get(serviceId);
String methodMapKey = getMethodMapKeyWithObjArr(methodName, paras);
//同样的方式,构建一个StringBuilder
return map.get(methodMapKey);
}
/**
* 放入一个实例
*
* @param serviceId
* @param object
*/
public void putObject(String serviceId, Object object) {
mObjectMap.put(serviceId, object);
}
/**
* 取出一个实例
*
* @param serviceId
*/
public Object getObject(String serviceId) {
return mObjectMap.get(serviceId);
}
}
/**
* 自定义注解,用于注册业务类的
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ServiceId {
String value();
}
我利用一个单例的
Registry</