protobuf 是什么? 为什么要用到?
protobuf 是二进制存储 所以比 json传输更快 更易于跨平台开发 但是读写更麻烦
没关系,google已经帮我们处理好了 现在我们只用站在巨人的肩膀上就行
先来看一个简单的protobuf 类 类名定义为 Result 在Result 类中定义个对象
message PMessage {
int32 code = 1;
string name = 2;
}
int32对应 java的int int64对应java的long
然后把他导入android studio中 生成java文件
这里就不讲解了 自行百度
因为我项目是用retrofit2 + rxjava网络请求 所以就基于此来演示
1、解析
网络请求结果 ResponseBody
Result.PMessage pResult = Result.PMessage.newBuilder().mergeFrom(response.byteStream()).build();
简单吧 如果你是用其他http请求框架 都有请求结果转二进制流的方法 只需要把二进制流丢进 mergeFrom方法即可
mergeFrom看生成的java文件代码 此方法支持ByteString byte[] InputStream等
2、封装
看到这里,会不会想到 一个项目 跟后台网络通信肯定不会只涉及到一个 protobuf类 多个类该怎么封装解析代码呢?
我们来看看newBuilder()代码
在看看 DEFAULT_INSTANCE是什么
PMessage 是通过Builder来初始化的
在来看看Builder类型
是google定义的
com.google.protobuf.GeneratedMessageV3.Builder
那么开始封装解析库
先改造下上面的类
message PMessage {
int32 code = 1; //公共响应码
string name = 2; //data对应的protobuf类
bytes data = 3; // 特定的protobuf类数据
}
假设我们需要解析个类 aaaa
message aaaa{
int32 age= 1;
string name = 2;
}
那么PMessage中 name就是aaaa data即是aaaa对象的bytes数据 自行跟后台定义好
public class HttpResultAnalysis {
public static TreeMap> MessageMap =
new TreeMap<>();
static {
//需要解析的类 假设是 aaaa
MessageMap.put("aaaa", Result.aaaa.newBuilder());
}
public static void disposeResult(ResponseBody response,DisposeResultListener disposeResultListener){
try{
//解析基类
Result.PMessage result = Result.PMessage.newBuilder().mergeFrom(response.byteStream()).build();
//result中 name字段对应本地解析的className data对应本地对象的字节流
if (!TextUtils.isEmpty(result.getName())) {
com.google.protobuf.GeneratedMessageV3.Builder> mBuilder = MessageMap.get(result.getName());
if (mBuilder == null) {
throw new IllegalAccessException("protobuf类本地未定义");
}
/**
* 千万记得调用clear 否则会有重复数据 因为我是在上面静态块中调用newBuilder() 而不是在此处解析调用
*
* see newBuilder() -> toBuilder()->
*
* new Builder().mergeFrom(this) 看到了么 如果对象有值 则会先把本身的值重新赋值 在加入新数据
*/
Object c = mBuilder.clear().mergeFrom(result.getData()).build();
disposeResultListener.onSuccessObject(c);
//用自定义监听返回调用的地方 Result.PMessage pMessage = (Result.PMessage) e;即可获取数据
}
}catch (Exception e){
e.printStackTrace();
}
}
public interface DisposeResultListener {
void onSuccessObject(Object c);
}
}
简单封装就到这里了 可以根据实际情况来处理
3、本地创建对象
上面只是解析网络数据 本地该怎么初始化protobuf类呢
1、Result.PMessage pMessage = Result.PMessage.newBuilder().clear()
.setData(ByteString.copyFrom(new byte[]{}))
.setName("aaaa")
.build();
2、接上面解析回调
Result.PMessage pMessage = (Result.PMessage) c;
pMessage.toBuilder().setData(ByteString.copyFrom(new byte[]{})).build();
4、protobuf中 map类型是只可读 如果传递的map需要本地修改 需要自己定义个map类中转