記一次 protobuf-javalite 實踐

*・劮hong發表於2019-04-01

環境

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中安裝外掛:

image.png

#####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的語法都是參考網上教程,若有失誤,謝謝指正。 寫完後,點選

image.png
即可自動生成java檔案。

####生成目錄結構:

image.png

資料生成和解析

#####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
  }
}
複製程式碼

這樣簡單的應用就完成了。

專案中遇到問題與解決:

  1. 需要重利用資料:option allow_alias = true;
enum Test{
    option allow_alias = true;    
    test_value=2;
    duplicate_test_value=2;
}
複製程式碼

原本在enum中不能定義相同的值,但加入option allow_alias = true; 就可以了

  1. 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…

相關文章