Protobuf在Android下的使用说明

protobuf nano是一个比较新的Protobuf官方实现,很适合在android应用中使用,相比原来的java实现,减少代码量和方法数,原为了这个问题而用C++实现的朋友们,可以换到这个实现,避免尴尬。

定义.proto文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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;
}

常用的类型:bool, int32, float, double, and string
“= 1”, “= 2” 叫Tag,代表是编码时的编号,这个编号很重要,解码时也是根据这个编码来的。
尽量使用1-15范围内的Tag定义,16开始会占用更多的数据空间。建议使用嵌套或者repeated的方式来避免超过15。

  • required必填字段,如果创建数据对象时不传入参数,编码时就会抛出Exception
  • optional可选字段,可以不传入数据,或者设置默认值。

使用required要注意,如果你升级协议时把这个字段改为optional,接收方没有升级,你发送的数据对方将无法解释。因此 不建议 使用它,我们只使用optionalrepeated

官方的.proto文档,可以参考Protocol Buffer Language Guide

选择一个编译器

当你有了.proto文件后,你需要把它用编译器生成为一份代码。编译器有不同的平台/实现,我们这里选择protoc,它将会生成“bean”、“编解码”。

下载编译器

https://github.com/google/protobuf/releases 这里可以下载source到本地编译,也可以下载可执行文件。我选择了可执行文件 https://github.com/google/protobuf/releases/download/v3.2.0/protoc-3.2.0-osx-x86_64.zip 。下载后解压,运行$ bin/protoc --version,能正常显示版本。

执行编译器

执行

1
$ ./protoc -I $SRC_DIR --java_out=$JAVA_DIR $SRC_DIR/addressbook.proto

例如:

1
./protoc -I ../../proto --java_out=../../java ../../proto/addressbook.proto

建议生成javanano版本,这个版本特别适合android,生成的文件小非常多,当然性能是比java差一点点。

1
$ ./protoc -I $SRC_DIR --javanano_out=$JAVA_DIR $SRC_DIR/addressbook.proto

使用Java Protobuf API来读写消息

刚才生成的代码是编译不通过的,需要导入protobuf的jar包。
build.gradle中加入:

1
compile 'com.google.protobuf.nano:protobuf-javanano:3.1.0'

如果使用非nano版本可以用:

1
compile 'com.google.protobuf:protobuf-java:3.2.0'

这里推荐使用nano版本。

读取数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static List<AddressBookProtosNano.Person> list(Context context) throws Exception {

File bookFile = new File(context.getFilesDir(), "addressbook.data");

FileInputStream input = new FileInputStream(bookFile);
ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
byte[] buff = new byte[256];
int read = 0;
while ((read = input.read(buff)) != -1) {
arrayOutputStream.write(buff, 0, read);
}
// Read the existing address book.
AddressBook addressBook =
AddressBook.parseFrom(arrayOutputStream.toByteArray());

return Arrays.asList(addressBook.people);
}

写入数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public static void create(Context context, String name, String email, String number, String type) throws Exception {
File bookFile = new File(context.getFilesDir(), "addressbook.data");

// Add an address.
AddressBook addressBook = new AddressBook();
addressBook.people = new Person[]{
setPersonForAddress(name, email, number, type)};
Log.i(TAG, "addPeople:" + addressBook);

// Write the new address book back to disk.
FileOutputStream output = new FileOutputStream(bookFile);
byte[] serialized = MessageNano.toByteArray(addressBook);

try {
output.write(serialized);
Log.i(TAG, "File written size:" + serialized.length);
} finally {
output.close();
}
}

源码

参照官方的文档写了个sample的项目,详细可以去这里下载:https://github.com/itvincent-git/protobuf-sample

文章作者: Vincent Zhong
文章链接: https://www.itvincent.net/2017/03/28/protobuf-java-android-guildline/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 itVincent的博客