ProtoBuf是Google的一个开源项目。作用于数据存储、数据通信和语言无关平台无关,扩展便捷。它是一个灵活、高效、自动化的序列化和结构化数据格式,比XML协议的数据格式更小,更快和更简单。你可以定义你想要的数据结构,然后使用ProtoBuf提供的编译器生成相应平台的源代码,编译器自动化会生成读写你结构化数据代码,然后可以把源码应用于各种语言,你甚至可以在更新数据结构情况下不破坏已经部署基于老格式编译程序。
项目github地址
ProtoBuf英文文档说明
Android中使用
- Gradle依赖ProtoBuf库
根目录gradle引入classpath
dependencies {
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.0'
}
- 项目目录gradle依赖ProtoBuf库,依赖后可以自动编译定义好的proto文件,大大节省工作量。
apply plugin: 'com.google.protobuf'
protobuf {
protoc {
// Download from repositories
artifact = 'com.google.protobuf:protoc:3.2.0'
}
plugins {
javalite {
// The codegen for lite comes as a separate artifact
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.1"
compile 'com.google.protobuf:protobuf-java:3.0.0'
}
定义proto消息文件
创建一个.proto文件,一般做法是在main文件下创建一个proto用于存放pro文件。
这是官方给的实例如何定义proto的文件内容
option java_package = "com.jinwei.test.pb";
option java_outer_classname = "BaseProto";
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=集合
repeated PhoneNumber phones = 4;
}
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message AddressBook {
//repeated=集合
repeated Person people = 1;
}
option java_package = "com.jinwei.test.pb";
存放的包名 编译后源码生成在bild/generated/source/proto目录中
option java_outer_classname = "BaseProto";
生成后输出的类名,不写默认是文件名字大写开头。
message 消息类似于一个类。
proto的三个修饰符说明
required
对于required的字段而言,初值是必须要提供的,否则字段的便是未初始化的。在Debug模式的buffer库下编译的话,序列化话的时候可能会失败,而且在反序列化的时候对于该字段的解析会总是失败的。所以,对于修饰符为required的字段,请在序列化的时候务必给予初始化。optional
对于optional的字段而言,如果未进行初始化,那么一个默认值将赋予该字段,当然也可以指定默认值,如上述proto定义中的PhoneType字段类型。-
repeated
对于repeated的字段而言,该字段可以重复多个,google提供的这个addressbook例子便有个很好的该修饰符的应用场景,即每个人可能有多个电话号码。在高级语言里面,我们可以通过数组来实现,而在proto定义文件中可以使用repeated来修饰,从而达到相同目的。当然,出现0次也是包含在内的。其中字段标签标示了字段在二进制流中存放的位置,这个是必须的,而且序列化与反序列化的时候相同的字段的Tag值必须对应,否则反序列化会出现意想不到的问题。
proto中的type在不同编程语言中对应的类型
定义完内容后build下项目,生成的源文件会在图中的这个包中
使用Protocol
在网络传输中使用Proto是通过字节输出和输入,所以生成的源码会包含相关的编解码方法,内部已经封装好了编解码的一些具体实现,生成后的pro类文件里面已经自动生成了相应编解码的方法。
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//新构建一个对象
BaseProto.Person.Builder builder = BaseProto.Person.newBuilder();
//通过get set方法来访问字段
builder.getEmail();
builder.setEmail("email");
builder.setId(1);
}
生成的文件提供了相应的解码方法