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