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'
}
}
}
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'
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;
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了
proto2与proto3的语法不大一样,例如proto3中不需要required和optional修饰字段,而proto2是需要的,这里指定了proto2的语法版本。
这里指定了java_package属性,说明当protoc生成这个java类的包名为net.angrycode.bean
最后使用message定义了一个名为
Book的数据结构,或者说通讯协议。Book有3个字段其中id和name是必须的,而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();
.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());
}
}
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());
}
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());
}
}
}
到此运行项目检查时候成功显示
参考链接:
本文介绍了如何在Android Studio中集成Google Protocol Buffer(protobuf),并详细解析了proto2与proto3语法的区别,特别是proto3不再支持required和optional关键字。通过示例解释了import导入其他proto文件、int32、repeated、required和optional字段的用法,以及option选项中的java_package和java_outer_classname配置。

2089

被折叠的 条评论
为什么被折叠?



