Andorid Studio 集成 Google Protocol Buffer(简称protobuf)

来源:互联网 发布:添加网络打印机搜不到 编辑:程序博客网 时间:2024/06/16 17:20
Andorid Studio 集成 Google Protocol Buffer(简称protobuf)
一、配置gradle导如protobuf
1、项目的build.gradle文件中加入
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.0'

2、模块的build.gradle文件
顶部添加protobuf插件
apply plugin: 'com.google.protobuf'
android结点增加proto文件位置配置
sourceSets {
    main {
        proto {
            srcDir 'src/main/proto'
            include '**/*.proto'
        }
        java {
            srcDir 'src/main/java'
        }
    }
}
添加依赖
compile 'com.google.protobuf:protobuf-java:3.1.0'
compile 'com.google.protobuf:protoc:3.1.0'
增加protobuf结点
protobuf {
protoc {
    artifact = 'com.google.protobuf:protoc:3.1.0'
}
generateProtoTasks {
    all().each { task ->
        task.builtins {
            remove java
        }
        task.builtins {
            java {}
            // Add cpp output without any option.
            // DO NOT omit the braces if you want this builtin to be added.
            cpp {}
        }
    }
}
generatedFilesBaseDir = "$projectDir/src/generated"
}
到此为止我们的protobuf就加入成功了下面附上完整的代码
apply plugin: 'com.android.application'
apply plugin: 'com.google.protobuf'

android {
    compileSdkVersion 23
    buildToolsVersion "25.0.0"
    defaultConfig {
        applicationId "com.protobuf.vargo.protobuf"
        minSdkVersion 21
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    sourceSets {
        main {
            proto {
                srcDir 'src/main/proto'
                include '**/*.proto'
            }
            java {
                srcDir 'src/main/java'
            }
        }
    }
}
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:23.+'
    compile 'com.android.support.constraint:constraint-layout:1.0.0-beta4'
    testCompile 'junit:junit:4.12'
    compile 'com.google.protobuf:protobuf-java:3.1.0'
    compile 'com.google.protobuf:protoc:3.1.0'
}
protobuf {
    protoc {
        artifact = 'com.google.protobuf:protoc:3.1.0'
    }
    generateProtoTasks {
        all().each { task ->
            task.builtins {
                remove java
            }
            task.builtins {
                java {}
                cpp {}
            }
        }
    }
    generatedFilesBaseDir = "$projectDir/src/generated"
}

二、创建一个实例检验一下是否成功
1、创建proto文件
一般情况下在app/main目录下创建proto目录,用于放置.proto文件。本例中创建了一个book.proto
syntax = "proto2";
option java_package = "net.angrycode.bean";
package bean;
message Book {
    required int32 id = 1;
    required string name = 2;
    optional string desc = 3;
}
此时AS可能会提示该文件读不懂,要你下载protobuf可读插件,你点确定下载等一会就ok了

proto2proto3的语法不大一样,例如proto3中不需要requiredoptional修饰字段,而proto2是需要的,这里指定了proto2的语法版本。

这里指定了java_package属性,说明当protoc生成这个java类的包名为net.angrycode.bean

最后使用message定义了一个名为Book的数据结构,或者说通讯协议。Book有3个字段其中idname是必须的,而desc是可选字段。如果必选字段缺失,读写时会发生com.google.protobuf.UninitializedMessageException: Message was missing required fields异常
    
对于proto文件的解读也可以看下面的例子,我们有以下两个文件
student.proto
- option java_package = "com.shun";
- option java_outer_classname = "StudentProto";
-
- message Student {
-     required int32 id = 1;
-     optional string name = 2;
-     optional int32 age = 3;
- }
teacher.proto
- import "student.proto";
- option java_package = "com.shun";
- option java_outer_classname = "TeacherProto";
-
- message Teacher {
-     required int32 id = 1;
-     optional string name = 2;
-
-     repeated Student student_list = 3;
- }

这里我们遇到了一些比较奇怪的东西:

import,int32,repated,required,optional,option等

一个个来吧:

1)import表示引入其他的proto文件

2)required,optional表示字段是否可选,这个决定了该字段有无值的情况下protobuffer会进行什么处理。如果标志了required,但当处理时,该字段没有进行传值,则会报错;如果标志了optional,不传值则不会有什么问题。

3)repeated相信应该都看得懂了,就是是否重复,跟JAVA里面的list类似
4)message就是相当于class了

5)option表示选项,其中的java_package表示包名,即生成JAVA代码时使用的包名,java_outer_classname即为类名,注意这个类名不能跟下面的message中的类名相同。

至于还有其他的选项和相关类型的,请参观官方文档。

2、生成对应的Java或者C++文件
在Android Studio中Build菜单选中Make Project或者Reruild Project可以在app/build目录下生成对应的java文件
此时的文件结构图为

3、使用我们生成的java文件做我们想做的事情,无非是读、写操作
添加权限
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
在我们的activity onCreate()方法中创建一个Book实例
BookOuterClass.Book book = BookOuterClass.Book.newBuilder()
  .setId(1)
  .setName("Prime")
  .setDesc("Code Book")
  .build();
proto可以往外写,使用writeTo(OutputStream)方法,可以是本地文件流,也可以是网络流。这里写入文件流
void save(BookOuterClass.Book book) {
        File dir = Environment.getExternalStorageDirectory();
        File file = new File(dir, "book");
        try {
            FileOutputStream outputStream = new FileOutputStream(file);
            book.writeTo(outputStream);
            outputStream.close();
        } catch (IOException e) {
            Log.e(TAG, e.getMessage());
        }
    }
proto是二进制传输,故可以读取文件流,或者网络流,这里文件模拟,使用parseFrom(byte[])方法。
void read() {
        File dir = Environment.getExternalStorageDirectory();
        File file = new File(dir, "book");
        try {
            FileInputStream inputStream = new FileInputStream(file);
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            byte[] data = new byte[1024];
            int len = -1;
            while ((len = inputStream.read(data)) != -1) {
                out.write(data, 0, len);
                out.flush();
            }
            BookOuterClass.Book book = BookOuterClass.Book.parseFrom(out.toByteArray());
            out.close();
            textView.setText("name:" + book.getName() + ",desc:" + book.getDesc());
        } catch (IOException e) {
            Log.e(TAG, e.getMessage());
        }
    }
全部代码为
package com.protobuf.vargo.protobuf;

import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.TextView;

import com.proto.bean.BookOuterClass;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        textView = (TextView) findViewById(R.id.textTest);

        BookOuterClass.Book book = BookOuterClass.Book.newBuilder()
                .setId(1)
                .setName("Prime")
                .setDesc("Code Book")
                .build();

        save(book);
        read();

    }
    private void save(BookOuterClass.Book book) {
        File dir = Environment.getExternalStorageDirectory();
        File file = new File(dir, "book");
        try {
            FileOutputStream outputStream = new FileOutputStream(file);
            book.writeTo(outputStream);
            outputStream.close();
        } catch (IOException e) {
            Log.e(TAG, e.getMessage());
        }
    }

    private void read() {
        File dir = Environment.getExternalStorageDirectory();
        File file = new File(dir, "book");
        try {
            FileInputStream inputStream = new FileInputStream(file);
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            byte[] data = new byte[1024];
            int len = -1;
            while ((len = inputStream.read(data)) != -1) {
                out.write(data, 0, len);
                out.flush();
            }
            BookOuterClass.Book book = BookOuterClass.Book.parseFrom(out.toByteArray());
            out.close();
            textView.setText("name:" + book.getName() + ",desc:" + book.getDesc());
        } catch (IOException e) {
            Log.e(TAG, e.getMessage());
        }
    }
}
到此运行项目检查时候成功显示

参考链接:
http://www.cnblogs.com/angrycode/p/6238058.html
http://www.jianshu.com/p/3a543757d086
http://cxshun.iteye.com/blog/1974498
0 0