Android中使用protobuf

第一步Android中配置:

1.首先在项目的根目录下的build.gradle中添加依赖,我这里之前用的0.8.0版本,编译之后说我的版本不匹配需要0.8.6及以上的版本,所以后来添加了0.8.6的版本,如下:

buildscript {
        repositories {
            jcenter()
            mavenCentral()
        }
        dependencies {
            classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.6'
        }
    }

2.在app module的build.gradle中的头部添加插件如下:

2.1 gradle4.6及以上的使用如下这种格式:

plugins {
    id 'com.google.protobuf'
}

2.2 gradle4.4以上的使用如下这种格式:

apply plugin: 'com.google.protobuf'

3.在app module中的build.gradle中添加如下依赖:

​
dependencies {
    api 'com.google.protobuf:protobuf-java:3.5.1'
    api 'com.google.protobuf:protoc:3.5.1'
}

​

4.在app module中的与android同层级下添加如下代码:

protobuf {
    protoc {
        artifact = 'com.google.protobuf:protoc:3.5.1' // 也可以配置本地编译器路径
    }

    generateProtoTasks {
        all().each { task ->
            task.builtins {
                remove java
            }
            task.builtins {
                java {}// 生产java源码
            }
        }
    }
}

5.在app module中的与android下的sourceSet下添加如下代码:

sourceSets {
        main {
            java {
                srcDir 'src/main/java'
            }
            proto {
                srcDir 'src/main/proto' //指定.proto文件路径
            }
        }
    }

5.然后编写proto文件然后编译就会自动生成JavaClass的文件,相当于我们直接用Java编写的数据模型bean,不会显示在对应的文件目录下,可以直接调用的

通过以上的配置在Android中的配置就已经完成了

第二步  proto文件的处理

1.编写proto文件,以proto后缀的文件

syntax = "proto3";
import "google/protobuf/any.proto"; // 引用外部的message,可以是本地的,也可以是此处比较特殊的 Any
package com.test;
option java_package = "com.example.test.domin"; // 生成类的包名,注意:会在指定路径下按照该包名的定义来生成文件夹
option java_outer_classname="PersonClass"; // 生成类的类名,注意:下划线的命名会在编译的时候被自动改为驼峰命名

message Person {
    string name = 1;
    int32 id = 2;
    string email = 3;
    string phone = 4;
    Sex sex = 5; // 枚举类型 
    repeated PhoneNumber phone = 6; // 引用下面定义的 PhoneNumber 类型的 message  
    map<string, string> addresses = 7; // map 类型  
    repeated google.protobuf.Any details = 8; // 使用 google 的 any 类型 

    // 定义一个枚举  
    enum Sex {      
        DEFAULT = 0;      
        MALE = 1;      
        Female = 2;  
    } 

// 定义一个 message  
    message PhoneNumber {    
        string number = 1;    
        PhoneType type = 2;    
        
        enum PhoneType {      
            MOBILE = 0;      
            HOME = 1;      
            COMPANY = 2;    
        }  
        
    }
 

}

2.编译之后给生成的JavaClass文件赋值及调用

2.1本地数据赋值

​
​
PersonClass.Person.Builder personBuilder =PersonClass.Person.newBuilder();
        personBuilder.setName("张浩");
        personBuilder.setEmail("xxxxx@163.com");
        personBuilder.setPhone("13888888888");
        personBuilder.setSex(PersonClass.Person.Sex.MALE);

        // 内部的 PhoneNumber 构造器
        PersonClass.Person.PhoneNumber.Builder phoneNumberBuilder = 
        PersonClass.Person.PhoneNumber.newBuilder();

            // PhoneNumber 赋值
            phoneNumberBuilder.setType(PersonClass.Person.PhoneNumber.PhoneType.MOBILE);
            phoneNumberBuilder.setNumber("17717037257");

            // person 设置 PhoneNumber
            personBuilder.addPhone(phoneNumberBuilder);

            // 生成 person 对象
            PersonClass.Person person = personBuilder.build();

​

​

2.2网络获取数据进行数据解析及赋值

Request request = new Request.Builder().url(url).build();
Call call = okHttpClient.newCall(request);
Response response = call.execute();

if (response.isSuccessful()) {
    ResponseBody responseBody = response.body();
    if (responseBody != null) {
        return Person.parseFrom(responseBody.byteStream());
    }
}

3.对编译后的生成JavaClass类进行序列化

3.1 byte[]类型的序列化和反序列化

​
//byte[]序列化
byte[] bytes = person.toByteArray();

//byte[]反序列化
PersonClass.Person personResult = PersonClass.Person.parseFrom(bytes);
 System.out.println(String.format("反序列化后的信息,姓名:%s,性别:%d,手机号:%s", personResult .getName(), personResult .getSexValue(), personResult .getPhone(1).getNumber()));

​

3.2 ByteString类型的序列化和反序列化

​
//ByteString序列化
ByteString byteString = person.toByteString();
System.out.println(byteString.toString());

//ByteString反序列化
PersonClass.Person personResult = PersonClass.Person.parseFrom(byteString);
System.out.println(String.format("反序列化得到的信息,姓名:%s,性别:%d,手机号:%s", personResult.getName(), personResult.getSexValue(), personResult.getPhone(1).getNumber()));

​

3.3 InputStream类型的序列化和反序列化

​
//将一个或者多个protobuf 对象字节写入 stream

//序列化
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
person.writeDelimitedTo(byteArrayOutputStream);

//反序列化,从 steam 中读取一个或者多个 protobuf 字节对象
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
            PersonClass.Person personResult = PersonClass.Person.parseDelimitedFrom(byteArrayInputStream);
            System.out.println(String.format("反序列化得到的信息,姓名:%s,性别:%d,手机号:%s", personResult.getName(), personResult.getSexValue(), personResult .getPhone(1).getNumber()));

​

4.在Android 的UI组件中显示相关信息

tvPerson.setText("Name:"+personBuilder.getName()+"  Email:"+personBuilder.getEmail()+"  Phone"+personBuilder.getPhone());

第三步  proto部分语法相关说明

syntax:声明版本。例如上面syntax="proto3",如果没有声明,则默认是proto2。
package:声明包名.
import:导入包。类似于java,例如上面导入了google/protobuf/any.proto包。
java_package:指定生成的类应该放在什么Java包名下。如果你没有显式地指定这个值,则它简单地匹配由package 声明给出的Java包名,但这些名字通常都不是合适的Java包名 (由于它们通常不以一个域名打头),本示例中是放在com.example.test.domain下的。
java_outer_classname:定义应该包含这个文件中所有类的类名。如果你没有显式地给定则将通过把文件名转换为首字母大写来生成。例如上面例子编译生成的文件名和类名是PersonClass。
message:类似于java中的class关键字。
repeated:用于修饰属性,表示对应的属性是个array.

其他部分 

1. 关于数据匹配可以查看下表来自官网:

 2. 关于默认值


proto3 中,数据的默认值不再支持自定义,而是由程序自行推倒:

string:默认值为空
bytes:默认值为空
bools:默认值为 false
数字类型:默认值为 0
枚举类型: 默认为定义的第一个元素,并且编号必须为 0
message 类型:默认值为 DEFAULT_INSTANCE,其值相当于空的 message

​

3.在跟后端Server传输数据需要注意的事项

1.android端和Server端使用的protobuf版本最好需要一致,不然可能会有影响。
2.在android端生成的Login.java文件复制到Server端时,最好连包名一起复制,这样Login.java里面的路劲就不要更改了。
3. 双方通信之前,需要先定义通信格式和内容
4.Protobuf需要修改后,然后要重新编译
5.数据传输过程中需要转换,保密性比较好

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值