Android中使用Protobuf
简介
protocolbuffer(以下简称protobuf)是google 的是一种轻便高效的结构化数据存储格式,作用形同于xml和json。它独立于语言,独立于平台。google 提供了多种语言的实现:java、c#、c++、go 和 python,每一种实现都包含了相应语言的编译器以及库文件。由于它是一种二进制的格式,比使用 xml 进行数据交换快许多。可以把它用于分布式应用之间的数据通信或者异构环境下的数据交换。作为一种效率和兼容性都很优秀的二进制数据传输格式,可以用于诸如网络传输、配置文件、数据存储等诸多领域。
protobuf优点
Protobuf 有如 XML,不过它更小、更快、也更简单。你可以定义自己的数据结构,然后使用代码生成器生成的代码来读写这个数据结构。你甚至可以在无需重新部署程序的情况下更新数据结构。只需使用 Protobuf 对数据结构进行一次描述,即可利用各种不同语言或从各种不同数据流中对你的结构化数据轻松读写。
它有一个非常棒的特性,即“向后”兼容性好,人们不必破坏已部署的、依靠“老”数据格式的程序就可以对数据结构进行升级。这样您的程序就可以不必担心因为消息结构的改变而造成的大规模的代码重构或者迁移的问题。因为添加新的消息中的 field 并不会引起已经发布的程序的任何改变。
Protobuf 语义更清晰,无需类似 XML 解析器的东西(因为 Protobuf 编译器会将 .proto 文件编译生成对应的数据访问类以对 Protobuf 数据进行序列化、反序列化操作)。
使用 Protobuf 无需学习复杂的文档对象模型,Protobuf 的编程模式比较友好,简单易学,同时它拥有良好的文档和示例,对于喜欢简单事物的人们而言,Protobuf 比其他的技术更加有吸引力。
protobuf不足
Protbuf 与 XML 相比也有不足之处。它功能简单,无法用来表示复杂的概念。
XML 已经成为多种行业标准的编写工具,Protobuf 只是 Google 公司内部使用的工具,在通用性上还差很多。
由于文本并不适合用来描述数据结构,所以 Protobuf 也不适合用来对基于文本的标记文档(如 HTML)建模。另外,由于 XML 具有某种程度上的自解释性,它可以被人直接读取编辑,在这一点上 Protobuf 不行,它以二进制的方式存储,除非你有 .proto 定义,否则你没法直接读出 Protobuf 的任何内容。
使用流程
1.编写protobuf文件
package jjd;
option java_package = "Lt.messagePush.vo.hardware.req";
option java_outer_classname = "HwWifiToAppReqProto";
message HwWifiToAppReq{
required string serialNum=1;
required int64 userId = 2;
required string account=3;
required string password=4;
optional bool has4G=5;
optional bool is4G=6;
}
2.编译protobuf文件
利用wire-compiler-2.0.1-jar-with-dependencies.jar包可以直接编译protobuf文件
1.打开cmd进入jar包目录
2.输入:
java -jar -Dfile.encoding=UTF-8 wire-compiler-2.0.1-jar-with-dependencies.jar --proto_path=F:\protobuf --java_out=F:\protobuf ActivityDetailReq.proto
protobuf目录
cmd命令
-Dfile.encoding=UTF-8 : 指明生成的java文件编码是utf8,不指明的话,会使用系统编码。在win7系统默认gbk,会出现中文乱码。
--proto_path:proto文件路径
--java_out : java文件的生成目录。在此目录中根据protobuf中定义的包名来生成对应的包结构
根据包名生成对应的包结构
3.Android中使用protobuf传输
HwWifiToAppReq.Builder builder = new HwWifiToAppReq.Builder();
builder.serialNum(serialNum)
.userId(userId)
.account(wifiInfo.getSSID().replace("\"",""))
.password("")
.has4G(NetUtil.isSimReady(AppApplication.context))
.is4G(NetUtil.isMobileNet(AppApplication.context));
SocketManager.getInstance(context).sendRequest(MessageType.HARDWARE_WIFI_TO_APP, builder.build().toByteArray(), new OnMinaCallBackInterface() {
@Override
public void loading() {
}
@Override
public void success(MsgCmdVo msg) {
}
@Override
public void failed(int respCode) {
SocketManager.onLogin = false;
logInInterface.failed(respCode);
}
});
4.Android中解析protobuf
在我们的项目中是使用com.squareup.wire:wire-runtime:1.7.0来解析protobuf文件
import com.squareup.wire.Wire;
Wire wire = new Wire();
//vo.getMsg()是从云端下发的protobuf
HwGetWifiPush hwGetWifiPush = wire.parseFrom(vo.getMsg(), HwGetWifiPush.class);
loginPresenter.sendWifiInfoToApp(DEVICE_ID, hwGetWifiPush.userId);