首先介绍Protocol Buffer 和 javanao 的概念
Protocol Buffers (a.k.a., protobuf) are Google's language-neutral, platform-neutral, extensible mechanism for serializing structured data.
Protocol Buffer (又名,protobuf)是 Google 提供的一种语言中立,平台中立,可扩展的序列化/结构化数据的机制。
JavaNano is a special code generator and runtime library designed specially for resource-restricted systems, like Android. It is very resource-friendly in both the amount of code and the runtime overhead.
JavaNano是专门为资源受限系统(如Android)设计的特殊代码生成器和运行时库。 代码量和运行时开销都非常资源友好。
工作中接手的项目中,使用了Protocol Buffer javanano。查看编译生成的java类,会发现,javanano相比普通版本做了很大程度上的阉割,去掉了getter/setter方法、builder模式、Parser解析器。javanano直接解析并没有啥问题,而且很简单方便,但是,对于习惯了使用RxJava+Retrofit的我,使用工厂统一解析肯定是个硬性需求。所以问题来了,普通版本的转换工厂(com.squareup.retrofit2:converter-protobuf:2.3.0)是使用反射获取的Parser实例进行解析,javanano就使用不了,所以就有了这个自定义转换工厂。
创建工厂
工厂类包含对ResponseBody/RequestBody两种类型的转换。
首先,是对ResponseBody响应消息的解析转换
public Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
//判断type是否是class
if (!(type instanceof Class<?>)) {
return null;
}
Class<?> c = (Class<?>) type;
//判断type是否是MessageNano的实现类
if (!MessageNano.class.isAssignableFrom(c)) {
return null;
}
//把c传递过去,以便在convert时创建T的实例
return new ProtoNanoResponseBodyConverter<>(c);
}
ResponseBody对应的转换器
final class ProtoNanoResponseBodyConverter<T extends MessageNano>
implements Converter<ResponseBody, T> {
private Class<?> c;
public ProtoNanoResponseBodyConverter(Class<?> c) {
this.c = c;
}
@Override
public T convert(@NonNull ResponseBody value) throws IOException {
T msg = null;
try {
//noinspection unchecked
msg = (T) c.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
assert msg != null;
//当然,最后还是使用mergeFrom方法,将Response中的字节写入上面创建的实例msg
return T.mergeFrom(msg, value.bytes());
}
}
然后是对RequestBody的转换,判断条件和ResponseBody相同
@Override
public Converter<T, RequestBody> requestBodyConverter
(Type type, Annotation[] parameterAnnotations,
Annotation[] methodAnnotations, Retrofit retrofit) {
if (!(type instanceof Class<?>)) {
return null;
}
if (!MessageNano.class.isAssignableFrom((Class<?>) type)) {
return null;
}
return new ProtoNanoRequestBodyConverter<>();
}
ResponseBody对应的转换器
class ProtoNanoRequestBodyConverter<T extends MessageNano> implements Converter<T, RequestBody> {
private static final MediaType MEDIA_TYPE = MediaType.parse("application/x-protobuf");
@Override
public RequestBody convert(@NonNull T value) throws IOException {
//调用MessageNano的toByteArray转换成字节流
return RequestBody.create(MEDIA_TYPE, MessageNano.toByteArray(value));
}
}
使用简介
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client.build())
.addConverterFactory(ProtoNanoConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
和所有工厂类的使用一样简单。
All in all
自定义工厂的过程非常简单,实质上只是对T.mergeFrom(msg, value.bytes())
和MessageNano.toByteArray(value)
的进一步封装,统一在创建retrofit对象的使用加入转换逻辑,不必每次在回调里再行处理。