环境
windows 10 AndroidStudio 3.0.1 protobuf-javalite 版本
初始配置
1. project.gradle
- dependencies {
- classpath 'com.android.tools.build:gradle:3.0.1'
- // protobuf支持版本,AS3.0必须用0.8.2以上
- classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.8'
-
- // NOTE: Do not place your application dependencies here; they belong
- // in the individual module build.gradle files
- }
- 复制代码
2. modle.gradel
- apply plugin: 'com.google.protobuf'
- android {
- sourceSets {
- main {
- proto {
- srcDir 'src/main/proto' //proto文件所在路径
- include '**/*.proto'
- }
- java {
- srcDir 'src/main/java'
- }
- }
- }
- }
-
- protobuf {
- protoc {
- // You still need protoc like in the non-Android case
- artifact = 'com.google.protobuf:protoc:3.0.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.builtins {
- // In most cases you don't need the full Java output
- // if you use the lite output.
- remove java
- }
- task.plugins {
- javalite { }
- }
- }
- }
- //将会在 "$projectDir/src/generated"这个目录中自动生成对应的java文件
- generatedFilesBaseDir = "$projectDir/src/generated"
- }
- dependencies {
- compile 'com.google.protobuf:protobuf-lite:3.0.0'
- }
- 复制代码
3. AndroidStudio中安装插件:
4. 编写.proto文件
因为在gradle中设置了proto文件的可编译目录,所以需要在这个目录中编写.proto文件 (参考网上教程写了proto文件,但具体网址不记得了,不好意思,如果需要我会备注)
- syntax = "proto3";
- package tutorial;
-
- option java_package = "com.je.pro.test";
- option java_outer_classname = "ResponsePB";
-
- message Tab {
- int32 type = 1;
- string f = 2;
- }
- message ItemData {
- string sname = 1;
- string packageid = 2;
- repeated Tab tabs = 45;
- }
- message DataItem {
- int32 datatype = 1;
- ItemData itemdata = 2;
- }
- message Response {
- repeated DataItem data = 1;
- bool hasNextPage = 2;
- string dirtag = 3;
- }
- 复制代码
初次使用,proto的语法都是参考网上教程,若有失误,谢谢指正。 写完后,点击
生成目录结构:
数据生成和解析
1. 数据生成
代码:
- public byte[] testGetBytes(){
- ResponsePB.Tab.Builder tabBuilder = ResponsePB.Tab.newBuilder().setF("sss").setType(2);
- ResponsePB.ItemData.Builder itemData = ResponsePB.ItemData.newBuilder();
- itemData.setPackageid("222222");
- itemData.setSname("eiiii");
- itemData.addTabs(tabBuilder);
-
- ResponsePB.Response.Builder responseBuilder = ResponsePB.Response.newBuilder();
- responseBuilder.setHasNextPage(true);
- responseBuilder.setDirtag("soft");
- ResponsePB.DataItem.Builder dataItem = ResponsePB.DataItem.newBuilder().setDatatype(1).setItemdata(itemData);
-
- ResponsePB.Response response = responseBuilder.addData(dataItem).build();
- System.out.println(response.toString());
-
- byte[] out = response.toByteArray();
- return out;
- }
- 复制代码
打印出
- data {
- datatype: 1
- itemdata {
- packageid: "222222"
- sname: "eiiii"
- tabs {
- f: "sss"
- type: 2
- }
- }
- }
- dirtag: "soft"
- has_next_page: true
- 复制代码
1. 解析
代码:
- public void testDeBytes(){
- byte[] out = testGetBytes();
-
- try {
- ResponsePB.Response test = ResponsePB.Response.parseFrom(out);
-
- System.out.println(test.getData(0));
- } catch (InvalidProtocolBufferException e) {
- e.printStackTrace();
- }
- }
- 复制代码
打印出:
- datatype: 1
- itemdata {
- packageid: "222222"
- sname: "eiiii"
- tabs {
- f: "sss"
- type: 2
- }
- }
- 复制代码
这样简单的应用就完成了。
项目中遇到问题与解决:
- 需要重利用数据:option allow_alias = true;
- enum Test{
- option allow_alias = true;
- test_value=2;
- duplicate_test_value=2;
- }
- 复制代码
原本在enum中不能定义相同的值,但加入option allow_alias = true;
就可以了
- repeated变量使用 正确方式
- ResponsePB.Tab.Builder tabBuilder = ResponsePB.Tab.newBuilder().setF("sss").setType(2);
- ResponsePB.ItemData.Builder itemData = ResponsePB.ItemData.newBuilder();
- itemData.addTabs(tabBuilder);
- 复制代码
错误方式
- ResponsePB.Tab.Builder tabBuilder = ResponsePB.Tab.newBuilder().setF("sss").setType(2);
- ResponsePB.ItemData.Builder itemData = ResponsePB.ItemData.newBuilder();
- itemData.setTabs(0,tabBuilder);
- 复制代码
报异常:
- java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
-
- at java.util.ArrayList.rangeCheck(ArrayList.java:653)
- at java.util.ArrayList.set(ArrayList.java:444)
- at com.google.protobuf.ProtobufArrayList.set(ProtobufArrayList.java:96)
- at com.je.pro.test.ResponsePB$ItemData.setTabs(ResponsePB.java:590)
- at com.je.pro.test.ResponsePB$ItemData.access$1500(ResponsePB.java:429)
- at com.je.pro.test.ResponsePB$ItemData$Builder.setTabs(ResponsePB.java:881)
- at com.je.pro.ExampleUnitTest.testByte(ExampleUnitTest.java:91)
- 复制代码
这个异常可以参考ArrayList.set() 方法,不要怀疑,我真的直接set了 附上ArrayList add() set() 源码
- /**
- * Replaces the element at the specified position in this list with
- * the specified element.
- *
- * @param index index of the element to replace
- * @param element element to be stored at the specified position
- * @return the element previously at the specified position
- * @throws IndexOutOfBoundsException {@inheritDoc}
- */
- public E set(int index, E element) {
- if (index >= size)
- throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
-
- E oldValue = (E) elementData[index];
- elementData[index] = element;
- return oldValue;
- }
-
- /**
- * Appends the specified element to the end of this list.
- *
- * @param e element to be appended to this list
- * @return <tt>true</tt> (as specified by {@link Collection#add})
- */
- public boolean add(E e) {
- ensureCapacityInternal(size + 1); // Increments modCount!!
- elementData[size++] = e;
- return true;
- }
- 复制代码
参考网站
developers.google.com/protocol-bu… github.com/google/prot… github.com/protocolbuf…