Android和Java的轻巧Wire协议缓冲器
Wire协议缓冲器 一个人必须有一个代码! -奥马尔小 由于我们的团队和项目增长,数据的种类和数量也随之增加。 成功将您简单的数据模型转换为复杂的! 无论您的应用程序将数据存储到磁盘或网络传送信号,该数据的结构和解释应该是清楚的。 消费者最好的工作,
Wire协议缓冲器
“一个人必须有一个代码!” -奥马尔小
由于我们的团队和项目增长,数据的种类和数量也随之增加。成功将您简单的数据模型转换为复杂的!无论您的应用程序将数据存储到磁盘或网络传送信号,该数据的结构和解释应该是清楚的。消费者最好的工作,他们了解的数据!
架构描述和文档数据模型。如果你有数据,你应该有一个架构。
协议缓冲器
谷歌的协议缓冲器都围绕一个伟大的模式语言:
它的跨平台和语言无关。无论您使用的编程语言,你就可以使用原架构与应用程序。
原始模式是向后兼容的,面向未来的。作为您的应用程序失去旧的功能和获得新的可以发展你的架构。
它的重点。原架构描述你的数据模型。而已。
下面是一个示例消息定义:
syntax = "proto2"; package squareup.dinosaurs; option java_package = "com.squareup.dinosaurs"; import "squareup/geology/period.proto"; message Dinosaur {
// Common name of this dinosaur, like "Stegosaurus".
optional string name = 1; // URLs with images of this dinosaur.
repeated string picture_urls = 2; optional squareup.geology.Period period = 5;
}
这里是一个枚举定义:
syntax = "proto2"; package squareup.geology; option java_package = "com.squareup.geology"; enum Period {
// 145.5 million years ago — 66.0 million years ago.
CRETACEOUS = 1; // 201.3 million years ago — 145.0 million years ago.
JURASSIC = 2; // 252.17 million years ago — 201.3 million years ago.
TRIASSIC = 3;
}
这种模式语言是Protocol Buffers的'最大的特点。你甚至可以用它纯粹是为了文档的目的,如描述一个JSON API。
协议缓冲器还定义了符合模式的消息的紧凑二进制编码。这种编码快速编码,快速解码,小到传输,和小存储。二进制编码使用数字标签从架构,像5
的时间
以上。
例如,我们的编码这个恐龙:
{
name: "Stegosaurus",
period: JURASSIC
}
编码值仅仅是15个字节:
Hex Description
0a tag: name(1), field encoding: LENGTH_DELIMITED(2). 1 << 3 | 2
0b "Stegosaurus".length()
53 'S'
74 't'
65 'e'
67 'g'
6f 'o'
73 's'
61 'a'
75 'u'
72 'r'
75 'u'
73 's'
28 tag: period(5), field encoding: VARINT(0). 5 << 3 | 0
02 JURASSIC(2)
为什么网?
该协议缓冲器模式语言和二进制编码都是由谷歌定义。Wire是从广场的独立实现,它是专门针对Android和Java设计的。
对于在架构中定义的每个消息的类型,电线产生一个不可变模型类和它的建造者。生成的代码看起来像你手工编写代码:它的记录,格式化和简单。电线的API,应该感到在家里谁喜欢程序员有效的Java。
尽管如此,也有一些有趣的设计决策线:
电线消息宣布
公众最终
场,而不是通常的getter方法。这减少了生成的代码和代码执行。更少的代码是Android程序特别有利。电线避免的情况下映射。声明为字段
picture_urls
在架构产生一个Java领域picture_urls
,而不是传统的pictureUrls
骆驼情况。虽然名字起初感到尴尬,它每次使用是梦幻般的grep
或更复杂的搜索工具。,Java源代码和数据模式之间航行时没有更多的映射。它还提供了一个善意提醒调用代码,原消息是有点特殊。基本类型总是装箱。如果字段不存在,它的价值是
零
。这是用于自然可选字段,如恐龙,其周期是未知的。字段也可以为空,由于模式演变:如果明天我们添加一个食肉动物
布尔给我们的消息定义,今天的数据不会有该字段的值。
下面是在紧凑型生成的代码恐龙
上述定义的消息:
通过Wire协议缓冲编译器生成的代码//,不编辑。
//源文件:squareup /恐龙/ dinosaur.proto在9:1
package com.squareup.dinosaurs; import com.squareup.geology.Period;
import com.squareup.wire.Message;
import com.squareup.wire.ProtoAdapter;
import com.squareup.wire.WireField;
import java.util.List;
import okio.ByteString; public final class Dinosaur extends Message<Dinosaur, Dinosaur.Builder> {
public static final ProtoAdapter<Dinosaur> ADAPTER = ProtoAdapter.newMessageAdapter(Dinosaur.class); private static final long serialVersionUID = 0L; public static final String DEFAULT_NAME = ""; public static final Period DEFAULT_PERIOD = Period.CRETACEOUS; /**
* Common name of this dinosaur, like "Stegosaurus".
*/
@WireField(
tag = 1,
adapter = "com.squareup.wire.ProtoAdapter#STRING"
)
public final String name; /**
* URLs with images of this dinosaur.
*/
@WireField(
tag = 2,
adapter = "com.squareup.wire.ProtoAdapter#STRING",
label = WireField.Label.REPEATED
)
public final List<String> picture_urls; @WireField(
tag = 5,
adapter = "com.squareup.geology.Period#ADAPTER"
)
public final Period period; public Dinosaur(String name, List<String> picture_urls, Period period) {
this(name, picture_urls, period, ByteString.EMPTY);
} public Dinosaur(String name, List<String> picture_urls, Period period, ByteString unknownFields) {
super(unknownFields);
this.name = name;
this.picture_urls = immutableCopyOf("picture_urls", picture_urls);
this.period = period;
} @Override
public Builder newBuilder() {
Builder builder = new Builder();
builder.name = name;
builder.picture_urls = copyOf("picture_urls", picture_urls);
builder.period = period;
builder.addUnknownFields(unknownFields());
return builder;
} @Override
public boolean equals(Object other) {
if (other == this) return true;
if (!(other instanceof Dinosaur)) return false;
Dinosaur o = (Dinosaur) other;
return equals(unknownFields(), o.unknownFields())
&& equals(name, o.name)
&& equals(picture_urls, o.picture_urls)
&& equals(period, o.period);
} @Override
public int hashCode() {
int result = super.hashCode;
if (result == 0) {
result = unknownFields().hashCode();
result = result * 37 + (name != null ? name.hashCode() : 0);
result = result * 37 + (picture_urls != null ? picture_urls.hashCode() : 1);
result = result * 37 + (period != null ? period.hashCode() : 0);
super.hashCode = result;
}
return result;
} public static final class Builder extends com.squareup.wire.Message.Builder<Dinosaur, Builder> {
public String name; public List<String> picture_urls; public Period period; public Builder() {
picture_urls = newMutableList();
} /**
* Common name of this dinosaur, like "Stegosaurus".
*/
public Builder name(String name) {
this.name = name;
return this;
} /**
* URLs with images of this dinosaur.
*/
public Builder picture_urls(List<String> picture_urls) {
checkElementsNotNull(picture_urls);
this.picture_urls = picture_urls;
return this;
} public Builder period(Period period) {
this.period = period;
return this;
} @Override
public Dinosaur build() {
return new Dinosaur(name, picture_urls, period, buildUnknownFields());
}
}
}
在Java代码来创建和访问原车型是紧凑和可读性:
Dinosaur stegosaurus = new Dinosaur.Builder()
.name("Stegosaurus")
.period(Period.JURASSIC)
.build(); System.out.println("My favorite dinosaur existed in the " + stegosaurus.period + " period.");
每种类型都有一个对应ProtoAdapter
能够编码一个信息字节和解码字节回一个消息。
Dinosaur stegosaurus = ...
byte[] stegosaurusBytes = Dinosaur.ADAPTER.encode(stegosaurus); byte[] tyrannosaurusBytes = ...
Dinosaur tyrannosaurus = Dinosaur.ADAPTER.decode(tyrannosaurusBytes);
当访问一个字段,使用Wire.get()
与相应的默认更换空值:
Period period = Wire.get(stegosaurus.period, Dinosaur.DEFAULT_PERIOD);
这相当于如下:
Period period = stegosaurus.period != null ? stegosaurus.period : Dinosaur.DEFAULT_PERIOD;
生成代码带线
资讯的编译器通过一个Maven插件可用。把.proto
在项目的源代码 的src / main /原
目录中,然后用插件生成的.java
文件。该插件将生成的Java代码会自动添加到项目的源根。
<build>
<plugins>
<plugin>
<groupId>com.squareup.wire</groupId>
<artifactId>wire-maven-plugin</artifactId>
<version>${project.version}</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>generate-sources</goal>
</goals>
<configuration>
<protoFiles>
<param>squareup/dinosaurs/dinosaur.proto</param>
<param>squareup/geology/period.proto</param>
</protoFiles>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
导线可以读取.proto
从本地文件系统,并从内的文件的.jar
文件。
编译器可以随意删改模式根类型及其传递依赖的一个子集。Java服务和Android应用程序可以使用每一个更大的共享模式的子集:共享模式时,项目之间,这很有用。
如果你不使用Maven,编译器也有一个命令行界面。刚刚替补 丝编译器版本-JAR与- dependencies.jar
同的路径罐子。
% java -jar wire-compiler-VERSION-jar-with-dependencies.jar \
--proto_path=src/main/proto \
--java_out=out \
squareup/dinosaurs/dinosaur.proto \
squareup/geology/period.proto
Writing com.squareup.dinosaurs.Dinosaur to out
Writing com.squareup.geology.Period to out
如果你使用Proguard的,那么你需要添加守
规则。最简单的方法是,告诉Proguard的不要碰线运行时库和产生的协议缓冲区(当然这些简单的规则将错过机会缩小和优化的代码):
-keep class com.squareup.wire.** { *; }
-keep class com.yourcompany.yourgeneratedcode.** { *; }
获得线
该线运行
包中包含了必须包含在使用线生成的代码的应用程序的运行时支持库。
使用Maven:
<dependency>
<groupId>com.squareup.wire</groupId>
<artifactId>wire-runtime</artifactId>
<version>2.1.1</version>
</dependency>
Android和Java的轻巧Wire协议缓冲器的更多相关文章
- 移动开发首页业界资讯移动应用平台技术专题 输入您要搜索的内容 基于Java Socket的自定义协议,实现Android与服务器的长连接(二)
在阅读本文前需要对socket以及自定义协议有一个基本的了解,可以先查看上一篇文章<基于Java Socket的自定义协议,实现Android与服务器的长连接(一)>学习相关的基础知识点. ...
- Android(java)学习笔记80:UDP协议发送数据
UDP协议发送数据:我们总是先运行接收端,再运行发送端发送端: 1 package cn.itcast_02; import java.io.IOException; import java.net. ...
- Android(java)学习笔记20:UDP协议发送数据
1. UDP协议发送数据:我们总是先运行接收端,再运行发送端发送端: package cn.itcast_02; import java.io.IOException; import java.net ...
- Android(java)学习笔记201:网络图片浏览器的实现(ANR)
1.我们在Android下,实现使用http协议进行网络通信,请求网络数据.这里是获取网络上的图片信息,让它可以显示在手机上: 但是我们这个手机连接网络是很费时间,如果我们在主线程(UI线程)中写这个 ...
- Android(java)学习笔记213:开源框架post和get方式提交数据(qq登录案例)
1.前面提到Http的get/post方式 . HttpClient方式,实际工作的时候不常用到,因为这些方式编写代码是很麻烦的 2.Android应用会经常使用http协议进行传输,网上会有很完善 ...
- Android(java)学习笔记205:网易新闻RSS客户端应用编写逻辑过程
1.我们的项目需求是编写一个新闻RSS浏览器,RSS(Really Simple Syndication)是一种描述和同步网站内容的格式,是使用最广泛的XML应用.RSS目前广泛用于网上新闻频道,bl ...
- Android(java)学习笔记257:JNI之helloword案例(利用NDK工具)
1.逻辑思路过程图: 2.下面通过一个HelloWorld案例来说明一下JNI利用NDK开发过程(步骤) 分析:我们在Win7系统下编译的C语言代码,我们知道C语言依赖操作系统,不能跨平台,所以我们要 ...
- Android(java)学习笔记148:网易新闻RSS客户端应用编写逻辑过程
1.我们的项目需求是编写一个新闻RSS浏览器,RSS(Really Simple Syndication)是一种描述和同步网站内容的格式,是使用最广泛的XML应用.RSS目前广泛用于网上新闻频道,bl ...
- Android(java)学习笔记144:网络图片浏览器的实现(ANR)
1.我们在Android下,实现使用http协议进行网络通信,请求网络数据.这里是获取网络上的图片信息,让它可以显示在手机上: 但是我们这个手机连接网络是很费时间,如果我们在主线程(UI线程)中写这个 ...
随机推荐
- Form.KeyPreview 属性
Form.KeyPreview 属性 今天再做KeyDown 和 KeyUp 事件时,就是忘了设置,窗体的KeyPreview 属性,所以KeyDown 和 KeyUp 事件没有反应(这里说明一下,本 ...
- C#中的OLEDB连接2
在通过ADO对Excel对象进行连接时(此时Excel则认为是一个数据源),需要配置对Excel数据源对应的连接串,这个连接串中包括了Provider信息(其实类似对数据库进行连接操作时,都需要指定连 ...
- ERP 推式 拉式 工序拉式 装配拉式 倒冲
ERP 推式 拉式 工序拉式 装配拉式 倒冲 以上為生产订单(wip)中的原料供应方式,最常用的有Pull和Push. PULL即拉动方式: 拉式生产是生产为主,原材料是由专门的配送人员按 ...
- usaco4.12Fence Rails(迭代加深)
为了这题还去学了下迭代加深 回来还是不会写 只好参考各大神的代码及题解了 二分枚举最大可以切的块数 然后就是各种分析及优化 USACO题解里写了7个优化.. 问题分析 抽象一下就可以发现,算法的本质是 ...
- WPF手写代码配置文件——单例
public class SettingHelper { //WPF下配置文件路径 public static readonly string SettingFilePath = AppDomain. ...
- Node.js 创建第一个应用
如果我们使用PHP来编写后端的代码时,需要Apache 或者 Nginx 的HTTP 服务器,并配上 mod_php5 模块和php-cgi. 从这个角度看,整个"接收 HTTP 请求并提供 ...
- 用友U8账套的建立
第1步点击开始菜单进入系统管理模块 第2步点击系统菜单下的注册 第3步弹出登录系统对话框,操作员输入admin点确定 第4步点击权限菜单下的用户 第5步进入用户管理窗口,点击工具栏 ...
- extjs获得store数据
var json = new Array(); for (var i = 0; i < storeEditFee.getCount(); i++) { json.push(storeEditFe ...
- 使用 testng.xml 参数化
1. 创建 Java 测试类 2. 添加测试方法 TestngParameterTest(String name, String age) 3. 为测试方法添加注释 @Parameters({&quo ...
- Cocos2d-x ios 下http请求的另一种实现
简单描述下需求:游戏要加入事件log,比如玩家升到10级:创建角色:或是,触发这些事件后要求客户端忘后台抛送一条log信息.一般情况下,我们可以直接使用cocos自带的HttpClient(底层用li ...