前言
在上一篇文章【Android最最简单】AIDL进阶(双向通信)中,已经向大家介绍了AIDL的进阶用法,用于service和client的双向调用,基本上可以满足大家的日常开发需求,且建立一套基于aidl实现的跨进程调用框架对于一个新需求或者一个新立项的项目,也完全没有什么难度,操起键盘代码一撸到底就是。但是,如果对于一个维护了N手的项目,突然要把已经实现了的N多需求转成跨进程实现,那就懵逼了,N多方法都需要用aidl实现,N多传输的bean类都要实现Parceable序列化,三N系列,想想就头大!
只要思想不滑坡,办法总比困难多!
解题思路
解题思路-1.0
实现一个通用接口,所有传输数据转json字符串,在接收数据后在进行拆箱还原成bean类,好了,完美解决,喜大普奔!此文over!
如此处理,虽然也不是不行,但这样简单,操作如此复杂,还要这篇文章干嘛!
解题思路-2.0
进入正题,最容易想到的方法是纯AIDL实现,接口文件一一对应,所有方法都编写AIDL接口文件实现!使用系列上一篇【Android最最简单】AIDL进阶(双向通信)介绍内容即可轻松实现。
- 优点:简单易懂。
- 缺点:
- 改造成本:成本高,比较适合新项目,不适合老项目;
- 后续维护:aidl接口文件和aidl序列化对象文件多,不利于维护。
解题思路-3.0
既然aidl可以传输数据,那么可不可以传输要调用的接口类名、方法名以及参数,在接收到数据后根据这些数据找到对应的实现类,执行方法然后返回结果呢?这样对调用者来说无感知,对提供者来说成本最小,可以简单发散一下思维,想象一下发起一次网络请求,我们只需要知道对应的url和对应的参数就可以了。
答案当然是可以了,要不然废话这么多干啥。是时候祭出今天的大杀器了——动态代理&反射!
杀猪刀-实操
1.创建双向通信
基于系列上一篇文章【Android最最简单】AIDL进阶(双向通信)中向大家介绍的进阶方法创建双向通信AIDL接口文件。
interface IService {
IPCResponse sendRequest(in IPCRequest request);
void attach(in IClientBridge iClientBridge);
}
interface IClientBridge {
IPCResponse sendRequest(in IPCRequest request);
}
模仿网络请求创建一个存储请求参数的接口类(IPCRequest)以及一个承载返回结果的接口类(IPCResponse),只需指定实现parcelable,具体实现类后续实现。
parcelable IPCRequest;
parcelable IPCResponse;
2.缓存实现对象
将实现object按实现接口名缓存对应的class、根据class缓存所有Method,并将object本身缓存。
public class IPCCache {
/**
* 保存服务端处理客户端请求的interfaces对应Class映射和内部的方法
*/
private final Map<String, Class<?>> mClazzs = new HashMap<>();
private final Map<Class<?>, HashMap<String, Method>> mMethods = new HashMap<>();
/**
* 保存服务端处理客户端请求的实例
*/
private final Map<String, WeakReference<Object>> mInstance = new HashMap<>();
/**
* 缓存对象及其方法
*
* @param object
*/
public void register(Object object) {
Class<?> clazz = object.getClass();
Class<?>[] interfaces = clazz.getInterfaces();
for (Class<?> cls : interfaces) {
mClazzs.put(cls.getName(), clazz);
}
// 缓存Method
HashMap<String, Method> method = new HashMap<>();
Method[] methods = clazz.getMethods();
for (Method m : methods) {
method.put(m.getName(), m);
}
mMethods.put(clazz, method);
addObject(clazz.getName(), object);
}
public void unRegister(Object object) {
Class<?> clazz = object.getClass();
Class<?>[] interfaces = clazz.getInterfaces();
for (Class<?> cls : interfaces) {
mClazzs.remove(cls.getName());
}
mMethods.remove(clazz);
removeObject(clazz.getName());
}
public Class<?> getClass(String interfacesName) {
if (TextUtils.isEmpty(interfacesName)) {
return null;
}
return mClazzs.get(interfacesName);
}
public Method getMethod(Class<?> clazz, String methodName) {
HashMap<String, Method> methods = mMethods.get(clazz);
return methods == null ? null : methods.get(methodName);
}
private void addObject(String className, Object object) {
mInstance.put(className, new WeakReference<>(object));
}
private void removeObject(String className) {
mInstance.remove(className);
}
public Object getObject(String className) {
return mInstance.containsKey(className) ? mInstance.get(className).get() : null;
}
}
3.动态代理[以client为例]
通过动态代理,将方法名、参数等封装成IPCRequest发送到service。
public <T> T get(Class<T> inter) {
if (null == mIpcService) {
return null;
}
// 获取处理客户端请求的对象的Key,以此在服务端找出对应的处理者
return (T) Proxy.newProxyInstance(getClass().getClassLoader(),
new Class[]{inter},
new ClientInvocationHandler(inter.getName()));
}
public class ClientInvocationHandler implements InvocationHandler {
private Gson mGson;
private String interfacesName;
public ClientInvocationHandler(String interfacesName) {
this.interfacesName = interfacesName;
mGson = new Gson();
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/*
当代理对象执行方法时,会走到这里
然后构造请求
转发给服务端
*/
IPCRequest ipcRequest = new IPCRequest();
ipcRequest.setInterfacesName(interfacesName);
ipcRequest.setMethodName(method.getName());
ipcRequest.setParameters(ParamsConvert.serializationParams(args));
IPCResponse ipcResponse = ClientManager.getInstance().sendRequest(ipcRequest);
if (ipcResponse != null && ipcResponse.isSuccess()) {
Class<?> returnType = method.getReturnType();
if (returnType != void.class && returnType != Void.class) {
return mGson.fromJson(ipcResponse.getResult(), returnType);
}
}
return null;
}
}
4.实现双向通信方法[以service端为例]
提供根据请求IPCRequest中携带的接口名、方法名以及参数,找到对应的实现类对象和Method,通过反射调用执行方法,并将结果返回。
@Override
public IPCResponse sendRequest(IPCRequest request) throws RemoteException {
try {
Class<?> aClass = ServiceManager.getInstance().getClass(request.getInterfacesName());
Object object = ServiceManager.getInstance().getObject(aClass.getName());
Method me = ServiceManager.getInstance().getMethod(aClass, request.getMethodName());
Object[] params = ParamsConvert.unSerializationParams(request.getParameters());
Object result = me.invoke(object, params);
String r = ParamsConvert.mGson.toJson(result);
return new IPCResponse(r, "执行方法成功", true);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}