ProtoBuf在Android中的简单使用
ProtoBuf是Google的一个开源项目。作用于数据存储、数据通信和语言无关平台无关,扩展便捷。它是一个灵活、高效、自动化的序列化和结构化数据格式,比XML协议的数据格式更小,更快和更简单。你可以定义你想要的数据结构,然后使用ProtoBuf提供的编译器生成相应平台的源代码,编译器自动化会生成读写你结构化数据代码,然后可以把源码应用于各种语言,你甚至可以在更新数据结构情况下不破坏已经部署基于老格式编译程序。
项目github地址
ProtoBuf语法指南
Android中使用
- 根目录gradle引入classpath
dependencies {
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.8'
}
-
app目录gradle依赖ProtoBuf库,依赖后可以自动编译定义好的proto文件,大大节省工作量。
apply plugin: 'com.android.application'后加上apply plugin: 'com.google.protobuf'
apply plugin: 'com.google.protobuf'
protobuf {
protoc {
artifact = 'com.google.protobuf:protoc:3.0.0'
}
plugins {
javalite {
artifact = 'com.google.protobuf:protoc-gen-javalite:3.0.0'
}
}
generateProtoTasks {
all().each { task ->
task.plugins {
javalite {}
}
}
}
}
dependencies {
compile "com.google.protobuf:protobuf-lite:3.0.0"
}
定义proto消息文件
创建一个.proto文件,一般做法是在main文件下创建一个proto用于存放pro文件。
1563958882333.png这是官方给的实例如何定义proto的文件内容
syntax = "proto2";
package tutorial;
option java_package = "com.example.tutorial";
option java_outer_classname = "AddressBookProtos";
message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
required string number = 1;
optional PhoneType type = 2 [default = HOME];
}
repeated PhoneNumber phones = 4;//数组
}
message AddressBook {
repeated Person people = 1;
}
option java_package = "com.example.tutorial";
存放的包名 编译后源码生成在bild/generated/source/proto目录中
option java_outer_classname = "AddressBookProtos";
生成后输出的类名,不写默认是文件名字大写开头。
message 消息类似于一个类。
proto的三个修饰符说明
-
required
对于required的字段而言,初值是必须要提供的,否则字段的便是未初始化的。在Debug模式的buffer库下编译的话,序列化话的时候可能会失败,而且在反序列化的时候对于该字段的解析会总是失败的。所以,对于修饰符为required的字段,请在序列化的时候务必给予初始化。 -
optional
对于optional的字段而言,如果未进行初始化,那么一个默认值将赋予该字段,当然也可以指定默认值,如上述proto定义中的PhoneType字段类型。 -
repeated
对于repeated的字段而言,该字段可以重复多个,google提供的这个addressbook例子便有个很好的该修饰符的应用场景,即每个人可能有多个电话号码。在高级语言里面,我们可以通过数组来实现,而在proto定义文件中可以使用repeated来修饰,从而达到相同目的。当然,出现0次也是包含在内的。其中字段标签标示了字段在二进制流中存放的位置,这个是必须的,而且序列化与反序列化的时候相同的字段的Tag值必须对应,否则反序列化会出现意想不到的问题。
proto中的type在不同编程语言中对应的类型
img类型表
定义完内容后build下项目,生成的源文件会在图中的这个包中
1563959294626.png使用Protocol
通过对比fastjson和gson的序列化耗时能够得出来protocol要更优秀
private void protoTest(){
AddressBookProtos.Person.PhoneNumber.Builder builder
= AddressBookProtos.Person.PhoneNumber.newBuilder().setNumber("110");
AddressBookProtos.Person.Builder zs = AddressBookProtos.Person.newBuilder()
.setName("张三")
.setId(1)
.addPhones(builder);
AddressBookProtos.Person.PhoneNumber.Builder builder1
= AddressBookProtos.Person.PhoneNumber.newBuilder().setNumber("120");
AddressBookProtos.Person.Builder ls = AddressBookProtos.Person.newBuilder()
.setName("李四")
.setId(2)
.addPhones(builder1);
AddressBookProtos.AddressBook addressBook = AddressBookProtos.AddressBook.newBuilder()
.addPeople(zs)
.addPeople(ls).build();
long l = System.currentTimeMillis();
byte[] bytes = addressBook.toByteArray();
Log.e(TAG, "protobuf 序列化耗时:" + (System.currentTimeMillis() - l));
Log.e(TAG, "protobuf 序列化数据大小:" + bytes.length);
try {
l = System.currentTimeMillis();
AddressBookProtos.AddressBook.parseFrom(bytes);
Log.e(TAG, "protobuf 反序列化耗时:" + (System.currentTimeMillis() - l));
} catch (InvalidProtocolBufferException e) {
e.printStackTrace();
}
JsonTest.fastJson();
JsonTest.gson();
}
使用TCP通信时可以通过protobuf进行数据的序列化与反序列化,降低数据传输量。加快传输速度,可通过自定义通信协议,处理TCP通信过程中的分包粘包问题。
网友评论