Wire Protocol Buffers介绍

来源:互联网 发布:数据新闻比赛官网 编辑:程序博客网 时间:2024/05/20 18:50

这是网上介绍Wire Protocol Buffers的东东,貌似对减少android应用的64k限制有一定作用,按照自己的理解把它翻译了一下,感觉还是很别扭。。。

什么是Wire ?

线是谷歌协议缓冲区的一个全新的,开源成果。它用于安卓设备,也可用于任何运行的java语言代码的地方。

在Square看来,我们广泛使用协议缓冲区。协议缓冲区是语言和平台的集合,它用来描述和传输数据。开发者可以在不同的环境中使用相同的架构,包括我们关心的Square的

环境。如Java和Ruby的服务器,Android和iOS设备。

协议缓冲区.proto源文件是可读的,它包含注释,能够正确记录你的框架在哪些地方定义。协议缓冲区定义了一个精简的二进制wire 格式,它允许框架不断开现有客户端进行扩

展。通常,一个代码生成器是用来读取.proto文件,并在你选择的语言中放出源代码。这种方法有利于提高开发,在你的application能够轻松使用相同的语言解释目标代码。允

许工具如IDE自动完成它们的全部工作。


线特性

当我们开始运行安装在android apps的标准线协议限制,我们希望需要的一系列特性能在未来的继承中实现:

消息应该包括生成方法的最小数量。

信息应该是全新的,数据对象对开发者友好性:

他们应该是高度可读的

他们应该是深度不可改变的

他们应该有某种意义上相等,hashCode,toString方法,

他们应该支持连锁的建造模式

他们应该从.proto源文件中继承文档。

协议缓冲区枚举映射到Java的枚举枚

理想情况下,一切都应该能够使用基于Java的工具进行构建。

在我们决定建立一个新的库之前,参考几个备选方案,包括最近的Nano android 协议缓冲库。虽然Nano协议缓冲区产生很少的方法,但它没有达到我们另外的目标。最终,我

们决定基于Square's ProtoParser  and  JavaWriter  libraries创建自己的库。在你的应用中可以很方便地使用产生的协议缓冲区作为成熟的数据对象。通过equals,

hashCode,和toString方法,信息可以得到Java集合。由于生成的代码是简洁的和紧凑的,单步进入调试模式不再是一个问题。因为你.proto文件的注释被复制到了生成java源

代码,因为在.proto文件的注释复制产生java源代码,在你的IDE有关消息和变量的记录时正确的。



减少方法计数

在过去,安卓开发者试图使用协议缓冲区已经付出了很高的代价。标准的协议缓冲区安装启用的时候在您的架构为每个可选或必需的字段产生至少九种方法(get, set, has, 和

clear的变种),至少十八种方法重复域!

这种非约束环境下的灵活性是很好的,任何需要的方法可能只是几个按键就自动完成。但在Android的Dalvik字节码格式环境强加一个单一的应用64K的方法的硬限制。对于

Square注册的应用程序,生成的协议缓冲区代码占用了我们的方法空间的很大一部分。通过使用Wire,我们删除了近10000种方法,从我们的应用程序中获得了大量的空间,

以增加新的功能。


Wire Example

考虑典型人类协议缓冲区定义:

message Person {  // The customer's full name.  required string name = 1;  // The customer's ID number.  required int32 id = 2;  // Email address for the customer.  optional string email = 3;  enum PhoneType {    MOBILE = 0;    HOME = 1;    WORK = 2;  }  message PhoneNumber {    // The user's phone number.    required string number = 1;    // The type of phone stored here.    optional PhoneType type = 2 [default = HOME];  }  // A list of the user's phone numbers.  repeated PhoneNumber phone = 4;}

Person类Wire生成如下(完全生成的代码是在这里):

message Person {  // The customer's full name.  required string name = 1;  // The customer's ID number.  required int32 id = 2;  // Email address for the customer.  optional string email = 3;  enum PhoneType {    MOBILE = 0;    HOME = 1;    WORK = 2;  }  message PhoneNumber {    // The user's phone number.    required string number = 1;    // The type of phone stored here.    optional PhoneType type = 2 [default = HOME];  }  // A list of the user's phone numbers.  repeated PhoneNumber phone = 4;}The Person class Wire generates is below (the complete generated code ishere):public final class Person extends Message {  /** The customer's full name. */  @ProtoField(tag = 1, type = STRING, label = REQUIRED)  public final String name;  /** The customer's ID number. */  @ProtoField(tag = 2, type = INT32, label = REQUIRED)  public final Integer id;  /** Email address for the customer. */  @ProtoField(tag = 3, type = STRING)  public final String email;  /**  A list of the user's phone numbers. */  @ProtoField(tag = 4, label = REPEATED)  public final List<PhoneNumber> phone;  private Person(Builder builder) {    super(builder);    this.name = builder.name;    this.id = builder.id;    this.email = builder.email;    this.phone = immutableCopyOf(builder.phone);  }  @Override public boolean equals(Object other) {    if (!(other instanceof Person)) return false;    Person o = (Person) other;    return equals(name, o.name)        && equals(id, o.id)        && equals(email, o.email)        && equals(phone, o.phone);  }  @Override public int hashCode() {    int result = hashCode;    if (result == 0) {      result = name != null ? name.hashCode() : 0;      result = result * 37 + (id != null ? id.hashCode() : 0);      result = result * 37 + (email != null ? email.hashCode() : 0);      result = result * 37 + (phone != null ? phone.hashCode() : 0);      hashCode = result;    }    return result;  }  public static final class Builder extends Message.Builder<Person> {    // not shown  }}

How it Works
消息类的实例只能由相应的嵌套生成器类创建,为了提供支持链接,Wire为每个变量产生一个单一的方法在每个生成器中。

Person person = new Person.Builder()    .name("Omar")    .id(1234)    .email("omar@wire.com")    .phone(Arrays.asList(new PhoneNumber.Builder()        .number("410-555-0909")        .type(PhoneType.MOBILE)        .build()))    .build();

Wire通过使用公共常量字段来减少每个消息字段的生成方法的数量。数组被封装,消息实例是不可改变的。每个字段都通过@ProtoField 注解提供Wire需要执行序列化和反序列化的元数据。

@ProtoField(tag = 1, type = STRING, label = REQUIRED)public final String name;

使用这些字段直接访问您的数据:

if (person.phone != null) {  for (PhoneNumber phone : person.phone)    if (phone.type == PhoneType.MOBILE) {      sendSms(person.name, phone.number, message);      break;    }  }}

我们创建上述代码序列化和反序列化Person类:

byte[] data = person.toByteArray();Wire wire = new Wire();Person newPerson = wire.parseFrom(data, Person.class);
序列化和反序列化,toString都是通过反射完成的,并加入了缓存来提高性能。
在标准协议缓冲区,你可以调用person.hasemail()看看电子邮件地址是否设置。使用Wire,你只需看看person.email = = null。重复的变量如手机,Wire要求你的应用可以获取或设置电话号码的列表,这节省了大量的方法。
Wire支持附加功能,如扩展和未知领域。目前,它缺乏支持一些先进的功能,包括自定义选项,服务和运行时的模式的反射。
Wire不支持过时的群组特性。


Try it out!
我们鼓励你尝试线,为代码作出贡献,让我们知道它是如何工作在您的应用程序!





























0 0