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>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM