集成protobuf
root build.gradle
buildscript {
repositories {
google()
jcenter()
mavenCentral()
}
dependencies {
classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.13"
}
}
app build.gradle
apply plugin: 'com.google.protobuf'
android {
sourceSets {
main {
java {
srcDir 'src/main/java'
}
proto {
srcDir 'src/main/proto'
include '**/*.proto'
}
}
}
}
dependencies {
implementation "com.google.protobuf:protobuf-javalite:4.0.0-rc-2"
}
protobuf {
protoc {
artifact = ""com.google.protobuf:protoc:4.0.0-rc-2"
}
generateProtoTasks {
all().each { task ->
task.builtins {
java {
option "lite"
}
}
}
}
}
集成wire
-
root build.gradle
buildscript{ repositories{ google() jcenter() mavenCentral() } dependencies{ classpath "com.squareup.wire:wire-gradle-plugin:3.3.0" } }
-
app build.gradle
apply plugin: 'com.squareup.wire' android{ ... sourceSets { main.java.srcDirs += "$buildDir/generated/source/wire" } ... } dependencies{ implementation "com.squareup.wire:wire-runtime:3.3.0" } wire{ kotlin{ android = true } } ktlint { ... filter { exclude { projectDir.toURI().relativize(it.file.toURI()).path.contains("/generated/") } } ... }
创建protobuf
先来看一下样例:
//设置protobuf的版本,当前最新的是proto3
syntax = "proto3";
//设置proto文件的命名空间
package Haley.Common;
//引入其他的proto文件(Java不支持)
//import "google/protobuf/any.proto";
//设置proto生成代码后的命令空间,AS编译默认会在/build/generated/source/proto/目录下生成java或kotlin的类文件
option java_package = "com.haley.test.data";
//这个名字不能与下文的message名字冲突,Person已经是一个message类型,就不能作为ClassName
option java_outer_classname = "Person";
//如果为true,每个message和service都会被生成为一个类。如果是false,则所有的message和service都将会是java_outer_classname的内部类. (默认false)
option java_multiple_files = true;
//是否生成Service,如果这个属性为false,将不会生成Service的代码,即使已经在proto文件编写了service结构(默认false)
option java_generic_services = true;
//对生成的代码的一种优化,有三个值:SPEED, CODE_SIZE, LITE_RUNTIME;
//表示希望生成代码是偏向执行速度,还是生成的文件大小,如果在app端,代码文件的大小是很重要的。
option optimize_for = SPEED;
//定义一个消息
message SimpleData {
// 字段规则:required -> 字段只能也必须出现 1 次 (proto3废弃了)
// 字段规则:optional -> 字段可出现 0 次或1次 (proto3废弃了)
// 字段规则:repeated -> 字段可出现任意多次(包括 0)
//字段规则 类型 名称 = 字段编号 [default = 默认值];
string text = 1;
int32 age = 2;
//数组
repeated double money = 3;
//map集合
map<string, int32> ages = 7;
//deprecated设置为ture,则表示不推荐使用该字段,Java会添加@Deprecated注释
int32 old_field = 6 [deprecated = true];
//定义一个枚举类型
enum Color{
RED = 0;
YELLOW = 1;
BLUE = 2;
}
Color color = 4;
//引用当前proto的message或import进来的proto的mesage
ImportData importData = 5;
//message也可以定义一个message,相当于内部类
message InnerData{
Color color = 3;
}
//这个内部类还可以引用外部类的
message InnerData2{
Color color = 4;
InnerData innerDate = 5;
ImportData importData = 6;
}
oneof Profession{//在使用时,下面的三个值,只能有一个值生效
string math = 8; //以最后一次设置的值为准,如果最后一次设置的值为math,那么Profession的值就是math
string compute = 9;//如果最后一次设置的值为compute,那么Profession的值就是compute
string chemistry = 10;
}
}
message ImportData{
bool value = 1;
}
//定义Rpc的Service,这里需要注意:下面的方法的传入参数和返回类型都必须是message,不能是string,int32等原始类型
service SimpleDataService{
rpc getSimpleData(ImportData) returns (SimpleData){}
}
protobuf 支持的基本类型
.proto Type | Notes | C++ Type | Java Type | Python Type[2] | Go Type | Ruby Type | C# Type | PHP Type | Dart Type |
---|---|---|---|---|---|---|---|---|---|
double | double | double | float | float64 | Float | double | float | double | |
float | float | float | float | float32 | Float | float | float | double | |
int32 | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint32 instead. | int32 | int | int | int32 | Fixnum or Bignum (as required) | int | integer | int |
int64 | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint64 instead. | int64 | long | int/long[3] | int64 | Bignum | long | integer/string[5] | Int64 |
uint32 | Uses variable-length encoding. | uint32 | int[1] | int/long[3] | uint32 | Fixnum or Bignum (as required) | uint | integer | int |
uint64 | Uses variable-length encoding. | uint64 | long[1] | int/long[3] | uint64 | Bignum | ulong | integer/string[5] | Int64 |
sint32 | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s. | int32 | int | int | int32 | Fixnum or Bignum (as required) | int | integer | int |
sint64 | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s. | int64 | long | int/long[3] | int64 | Bignum | long | integer/string[5] | Int64 |
fixed32 | Always four bytes. More efficient than uint32 if values are often greater than 228. | uint32 | int[1] | int/long[3] | uint32 | Fixnum or Bignum (as required) | uint | integer | int |
fixed64 | Always eight bytes. More efficient than uint64 if values are often greater than 256. | uint64 | long[1] | int/long[3] | uint64 | Bignum | ulong | integer/string[5] | Int64 |
sfixed32 | Always four bytes. | int32 | int | int | int32 | Fixnum or Bignum (as required) | int | integer | int |
sfixed64 | Always eight bytes. | int64 | long | int/long[3] | int64 | Bignum | long | integer/string[5] | Int64 |
bool | bool | boolean | bool | bool | TrueClass/FalseClass | bool | boolean | bool | |
string | A string must always contain UTF-8 encoded or 7-bit ASCII text, and cannot be longer than 232. | string | String | str/unicode[4] | string | String (UTF-8) | string | string | String |
bytes | May contain any arbitrary sequence of bytes no longer than 232. | string | ByteString | str | []byte | String (ASCII-8BIT) | ByteString | string |
序列化和反序列化
-
序列化成byte数组
SimpleData simpleData = SimpleData.newBuilder().setText("hello") .setAge(18) .setColor(SimpleData.Color.BLUE) .setImportData(ImportData.newBuilder().setValue(true).build()) .addMoney(100) .setOldField(111) .setMath("aaaa") .setCompute("bbbb") .setChemistry("cccc") .build(); System.out.println(simpleData); byte[] bytes = simpleData.toByteArray();
-
反序列化成对象
byte[] bytes = simpleData.toByteArray(); SimpleData simpleData1 = SimpleData.parseFrom(bytes); System.out.println(simpleData1);
DataStore Serializer
-
protobuf-javalite
object SimpleDataSerializer : Serializer<SimpleData> { override fun readFrom(input: InputStream): SimpleData { return try { SimpleData.parseFrom(input) } catch (exception: InvalidProtocolBufferException) { throw CorruptionException("Cannot read proto", exception) } } override fun writeTo(t: SimpleData, output: OutputStream) { t.writeTo(output) } }
-
wire
object SimpleDataSerializer : Serializer<SimpleData> { override fun readFrom(input: InputStream): SimpleData { return if (input.available() != 0) try { SimpleData.ADAPTER.decode(input) } catch (exception: IOException) { throw CorruptionException("Cannot read proto", exception) } else { SimpleData("") } } override fun writeTo(t: SimpleData, output: OutputStream) { SimpleData.ADAPTER.encode(output, t) } }