• JavaAndroid 中使用Protocol Buffers传输数据
    • 下载Protocol Buffers
    • 编写Proto文件
      • 参数声明
      • 参数类型
      • 补充说明
      • 最终的proto文件
    • 生成Java文件
    • 解析数据
    • 演示GIF

Java/Android 中使用Protocol Buffers传输数据

Protocol Buffers是一种数据交互格式,是Google公司开源的一种数据描述语言,能够将结构化数据序列化,可用于数据存储、通信协议等方面。相比于现在流行的XML以及Json格式存储数据,通过Protocol Buffers来定义的文件体积更小,解析速度更快(官方文档中明确提到),目前已经支持很多的主流语言,本篇文章主要介绍一下如何在Java/Android中使用。

Github地址

官方地址

下载Protocol Buffers

在官方地址或者maven仓库中下载即可。

编写Proto文件

本文采用官方文档中的例子来演示一下:官方文档例子地址
proto文件中,Message类似Java中的类,里面可以定义我们需要的属性:

message Person {  required string name = 1;  required int32 id = 2;  optional string email = 3;  enum PhoneType {    MOBILE = 0;    HOME = 1;    WORK = 2;  }  message PhoneNumber {    required string number = 1;    optional PhoneType type = 2 [default = HOME];  }  repeated PhoneNumber phone = 4;}

通过上面的官方例子,我们可以知道Protocol Buffers是支持枚举的。

参数声明

You specify that message fields are one of the following:    required: a well-formed message must have exactly one of this field.    optional: a well-formed message can have zero or one of this field (but not more than one).    repeated: this field can be repeated any number of times (including zero) in a well-formed message. The order of the repeated values will be preserved.
  • required:一个message中必须有一个的字段。

  • optional:一个message中可选的:可以有1一个也可以有0个。

  • repeated:在一个message中可以重复任意次(包括0),但是会保留他们的顺序。

    可以理解为Java中的集合

参数类型

下面是官方文档中定义proto格式的文件中参数的类型,与其他语言中的数据类型的对应关系:

proto Type C++ Type Java Type Python Type[2] Go Type
double double double float *float64
float float float float *float32
int32 int32 int int *int32
int64 int64 long int/long[3] *int64
uint32 uint32 int[1] int/long[3] *uint32
uint64 uint64 long[1] int/long[3] *uint64
sint32 int32 int int *int32
sint64 int64 long int/long[3] *int64
fixed32 uint32 int[1] int *uint32
fixed64 uint64 long[1] int/long[3] *uint64
sfixed32 int32 int int *int32
sfixed64 int64 long int/long[3] *int64
bool bool boolean bool *bool
string string String str/unicode[4] *string
bytes string ByteString str []byte

补充说明:

  • 可以在一个.proto文件中定义多个message类型。这在定义多个相关消息时非常有用:例如,如果要定义与SearchResponse消息类型相对应的回复消息格式,则可以将其添加到相同的.proto:
message SearchRequest {  required string query = 1;  optional int32 page_number = 2;  optional int32 result_per_page = 3;}message SearchResponse { ...}
  • 添加注释:可以在 // 后添加相关注释
To add comments to your .proto files, use C/C++-style // syntax.message SearchRequest {  required string query = 1;  optional int32 page_number = 2;// Which page number do we want?  optional int32 result_per_page = 3;// Number of results to return per page.}

最终的proto文件

这里依然选择采用官方文档中的例子,我们对其进行一些小改动,将包名和生成的类名改成我们自己的:

// See README.txt for information and build instructions.//// Note: START and END tags are used in comments to define sections used in// tutorials.  They are not part of the syntax for Protocol Buffers.//// To get an in-depth walkthrough of this file and the related examples, see:// https://developers.google.com/protocol-buffers/docs/tutorials// [START declaration]syntax = "proto3";package lhy;// [END declaration]// [START java_declaration]option java_package = "com.csdn.lhy";   //指定生成Java文件的包名option java_outer_classname = "PersonInfo"; //指定生成的Java文件的类名// [END java_declaration]// [START csharp_declaration]option csharp_namespace = "Google.Protobuf.Examples.AddressBook";// [END csharp_declaration]// [START messages]message Person {  string name = 1;  int32 id = 2;  // Unique ID number for this person.  string email = 3;  enum PhoneType {    MOBILE = 0;    HOME = 1;    WORK = 2;  }  message PhoneNumber {    string number = 1;    PhoneType type = 2;  }  repeated PhoneNumber phones = 4;}// Our address book file is just one of these.message AddressBook {  repeated Person people = 1;}// [END messages]

生成Java文件

这里就需要通过刚才下载过来的exe工具生成相应的文件:
命令行: proto.exe --java_out=./ ./addressbook.proto

我们可以看到在指定包的文件下生成了我们刚才指定的Java类:

这里要说明的是,addressbook.proto这个就是我们刚才定义的proto文件。

解析数据

我们需要将我们刚才下的jar包以及生成的Java文件拷贝到我们的项目中,实际在项目中,我们一般通过通过流来接受、发送数据,生成的Java文件中已经帮我们处理:

  • toByteArray():

    可以将该对象序列化为一个Byte数组,进而封装成流。

  • parseFrom():

    可以将一个byte数据或者流中解析出该Java类的对象。

示例代码:

package com.csdn.lhy.protobuffersdemo;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.view.View;import android.widget.Button;import android.widget.TextView;import java.io.ByteArrayInputStream;import java.io.IOException;import static com.csdn.lhy.protobuffersdemo.PersonInfo.Person.PhoneType.HOME;public class MainActivity extends AppCompatActivity{    private PersonInfo.Person lhy;    private Button serialize;    private Button deserialize;    private TextView tv_info;    @Override    protected void onCreate(Bundle savedInstanceState){        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        initView();    }    private void initView(){        serialize = (Button) findViewById(R.id.serialize);        deserialize = (Button) findViewById(R.id.deserialize);        tv_info = (TextView) findViewById(R.id.tv_info);        serialize.setOnClickListener(new View.OnClickListener(){            @Override            public void onClick(View v){                serializePerson();            }        });        deserialize.setOnClickListener(new View.OnClickListener(){            @Override            public void onClick(View v){                deserializePerson();            }        });    }    private void deserializePerson(){        try{            PersonInfo.Person dese_lhy = PersonInfo.Person.parseFrom(new ByteArrayInputStream(lhy.toByteArray()));            StringBuffer sb = new StringBuffer();            String newLine = "\n";            sb.append("Name: "+dese_lhy.getName());            sb.append(newLine);            sb.append("Id: "+ dese_lhy.getId());            sb.append(newLine);            sb.append("Phone Num: "+ dese_lhy.getPhones(0));            sb.append(newLine);            tv_info.setText(sb.toString());        }catch(IOException e){            e.printStackTrace();        }    }    private void serializePerson(){        //创建Person对象        lhy = PersonInfo.Person.newBuilder()                .setName("Lhy")                .setId(110)                .setEmail("Vive la Janee D'Arc")                .addPhones(PersonInfo.Person.PhoneNumber.newBuilder()                        .setNumber("120")                        .setType(HOME).build())                .build();    }}

演示GIF

更多相关文章

  1. 开源项目之Android DataFramework(数据库框架)
  2. Edittext在xml文件中设置android:focusable=“false”之后,edittex
  3. 【经验记录】Android上传文件到服务器
  4. Android studio查看SQLIte数据库文件
  5. Android 数据库事务的个人理解
  6. [图文]为移植到Android平台上的Cocos2d-x项目添加xml布局文件
  7. 使用openFileInput和openFileOutput实现Android平台的数据存储
  8. 今天开始写android的照片浏览器(一)至返回所有图片文件
  9. Android工程内嵌资源文件的两种方法

随机推荐

  1. 我的Android音乐播放器
  2. 多个 Android Drawable shape 组合画田字
  3. Android 修改EditText光标颜色
  4. Android系统Surface机制的SurfaceFlinger
  5. android之视频播放
  6. Android中drawable使用Shape资源
  7. Android:创建窗口式Activity
  8. 初始化有EditText或AutoCompleteEditText
  9. MPAndroidChart项目实战(七)——自定义横向
  10. android开发视频教程 android培训入门教