首先介紹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 提供的一種語言中立,平臺(tái)中立,可擴(kuò)展的序列化/結(jié)構(gòu)化數(shù)據(jù)的機(jī)制。
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是專門為資源受限系統(tǒng)(如Android)設(shè)計(jì)的特殊代碼生成器和運(yùn)行時(shí)庫(kù)。 代碼量和運(yùn)行時(shí)開銷都非常資源友好。
工作中接手的項(xiàng)目中,使用了Protocol Buffer javanano。查看編譯生成的java類,會(huì)發(fā)現(xiàn),javanano相比普通版本做了很大程度上的閹割,去掉了getter/setter方法、builder模式、Parser解析器。javanano直接解析并沒有啥問題,而且很簡(jiǎn)單方便,但是,對(duì)于習(xí)慣了使用RxJava+Retrofit的我,使用工廠統(tǒng)一解析肯定是個(gè)硬性需求。所以問題來了,普通版本的轉(zhuǎn)換工廠(com.squareup.retrofit2:converter-protobuf:2.3.0)是使用反射獲取的Parser實(shí)例進(jìn)行解析,javanano就使用不了,所以就有了這個(gè)自定義轉(zhuǎn)換工廠。
創(chuàng)建工廠
工廠類包含對(duì)ResponseBody/RequestBody兩種類型的轉(zhuǎn)換。
首先,是對(duì)ResponseBody響應(yīng)消息的解析轉(zhuǎn)換
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的實(shí)現(xiàn)類
if (!MessageNano.class.isAssignableFrom(c)) {
return null;
}
//把c傳遞過去,以便在convert時(shí)創(chuàng)建T的實(shí)例
return new ProtoNanoResponseBodyConverter<>(c);
}
ResponseBody對(duì)應(yīng)的轉(zhuǎn)換器
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;
//當(dāng)然,最后還是使用mergeFrom方法,將Response中的字節(jié)寫入上面創(chuàng)建的實(shí)例msg
return T.mergeFrom(msg, value.bytes());
}
}
然后是對(duì)RequestBody的轉(zhuǎn)換,判斷條件和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對(duì)應(yīng)的轉(zhuǎn)換器
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 {
//調(diào)用MessageNano的toByteArray轉(zhuǎn)換成字節(jié)流
return RequestBody.create(MEDIA_TYPE, MessageNano.toByteArray(value));
}
}
使用簡(jiǎn)介
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client.build())
.addConverterFactory(ProtoNanoConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
和所有工廠類的使用一樣簡(jiǎn)單。
All in all
自定義工廠的過程非常簡(jiǎn)單,實(shí)質(zhì)上只是對(duì)T.mergeFrom(msg, value.bytes())和MessageNano.toByteArray(value)的進(jìn)一步封裝,統(tǒng)一在創(chuàng)建retrofit對(duì)象的使用加入轉(zhuǎn)換邏輯,不必每次在回調(diào)里再行處理。