1、早期的Dalvik VM内部使用short类型变量来标识方法的id,dex限制了程序的最大方法数是65535,如果超过最大限制,无法编译,把dex.force.jumbo=true添加到project.properties文件中可以通过编译,在低端手机无法安装,报错误INSTALL_FAILED_DEXOPT。

2、dex文件解决8M时,低端机安装也会出现INSTALL_FAILED_DEXOPT错误,因为dexopt用了一个固定大小的缓冲区存储所有的方法名,2.3(含)之前的版本只有5M大小,最新的版本有8M或者16M

问题解决

1、如方法数量超过上线,必须精简方法数量。可以对复杂模块采用jni的方式实现,也可以对边缘模块采用本地插件化的方式解决。

2、如只是dex文件过大,可以采用混淆的方法减小dex文件尺寸,如混淆后还是过大,参考第一个方法。

上面的方式只能解决你在开发中遇到的问题, 并且治标不治本,下面的内容才是根本解决原文地址:http://corner.squareup.com/2013/08/introducing-wire.html

Introducing Wire Protocol Buffers

August 23, 2013

What is Wire?

Wire is a new, open-source implementation of Google's Protocol
Buffers
. It's meant for Android devices but can be used on anything that runs Java
language code.

At Square, we use Protocol Buffers extensively. Protocol Buffers are a language- and platform-neutral schema for describing
and transmitting data. Developers can use the same schemas across diverse environments, including the environments we care
about at Square, such as Java and Ruby servers and Android and iOS devices.

Protocol Buffer .proto source files are human-readable and can contain comments, so it's easy to document your schema right
where it is defined. Protocol Buffers define a compact binary wire format that allows schemas to evolve without breaking
existing clients. Typically, a code generator is used that reads .proto files, and emits source code in the language of
your choice. This approach helps to speed development since the resulting code is expressed in the same language as the rest
of your application, allowing tools such as IDE autocompletion to do their job fully.

Wire Features

As we began to run into limitations of the standard Protocol Buffer implementation in our Android apps, we made a wish list
of the features we wanted for a future implementation:

  • Messages should contain a minimum number of generated methods
  • Messages should be clean, developer-friendly data objects:
    • They should be highly readable
    • They should be deeply immutable
    • They should have meaningful equalshashCode, and toString methods
    • They should support the chained Builder pattern
    • They should inherit documentation from the .proto source files
    • Protocol Buffer enums should map onto Java enums
  • Ideally, everything should be buildable using Java-based tools

Before we decided to build a new library we looked at several alternatives, including the recent
Nano Android
Protocol Buffer library. While Nano Protocol Buffers generate very few methods, they didn't meet our other goals.
Ultimately, we decided to create our own library from scratch, built on Square's
ProtoParser and JavaWriter libraries.

It's handy to be able to use generated Protocol Buffer classes as full-fledged data objects in your app. By including
equalshashCode, and toString methods, messages can participate in Java collections. Since the generated code is clean
and compact, stepping into it in the debugger is not a problem. And because comments in your.proto files are copied into
the generated Java source code, the documentation for your messages and fields is right there in your IDE.

Reducing the Method Count  减少放法数量

In the past, Android developers attempting to use Protocol Buffers have paid a steep price. The standard Protocol Buffer
implementation (protoc) generates at least nine methods for each optional or required field in your schema (variants of
getsethas, and clear), and at least eighteen methods for repeated fields!

Having all this flexibility is great in non-constrained environments — whatever method you need is probably just a few
auto-completed keystrokes away. But in Android environments the Dalvik bytecode
format
 imposes a hard limit of 64K methods in a single
application. For the Square Register app, generated Protocol Buffer code was taking up a large chunk of our method space. By
switching to Wire, we removed almost 10,000 methods from our application and gained a lot of breathing room to add new
features.

Wire Example

Consider the classic Person protocol buffer definition:

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 is
here):

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

An instance of a message class can only be created by a corresponding nested Builder class. Wire generates a single method
per field in each builder in order to support chaining:

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 reduces the number of generated methods by using a public final field for each message field. (使用public final field的方式来减少方法数目)Arrays are wrapped, so
message instances are deeply immutable(Arrays被保护起来,这样才能稳定安全). Each field is annotated with a @ProtoField annotation providing metadata that
Wire needs to perform serialization and deserialization(使用标签的方式来描述元数据,这样就减少get set方法):

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

Use these fields directly to access your data:

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

The code to serialize and deserialize the Person we created above looks like this:

byte[] data = person.toByteArray();
Wire wire = new Wire();
Person newPerson = wire.parseFrom(data, Person.class);

Some features, such as serialization, deserialization, and the toString method are implemented using reflection(序列化和反序列化,toString都是通过反射完成的). Wire caches reflection information about each message class the first time it is encountered for better performance.(并加入了缓存来提高性能)

In standard Protocol Buffers, you would call person.hasEmail() to see if an email address has been set. In Wire, you simply check if person.email == null. For repeated fields such asphone, Wire also requires your app to get or set a List of
PhoneNumber instances all at once, which saves a lot of methods.(针对 repeated方法,做出的优化,减少了很多方法数)

Wire supports additional features such as extensions and unknown fields. At present, it lacks support for some advanced
features including custom options, services, and runtime introspection of schemas. These can be added in the future as use
cases for them on constrained devices emerge.

Wire deliberately does not support the obsolete 'groups' feature.

Try it out!

We encourage you to try Wire, contribute to the code, and let us know how it works in your apps!

针对android方法数64k的限制,square做出的努力。精简protobuf的更多相关文章

  1. (转载)Android 方法数超过64k、编译OOM、编译过慢解决方案。

    Android 方法数超过64k.编译OOM.编译过慢解决方案.   目前将项目中的leancloud的即时通讯改为环信的即时通讯.当引入easeui的时候 出现方法数超过上限的问题. 搜索一下问题, ...

  2. Android 方法数超过64k、编译OOM、编译过慢解决方案。

    目前将项目中的leancloud的即时通讯改为环信的即时通讯.当引入easeui的时候 出现方法数超过上限的问题. 搜索一下问题,解决方法很简单. 这里简单记录一下,顺序记录一下此解决方案导致的另一个 ...

  3. Android方法数超出限定的问题(multiDex,jumboMode)

    在Android项目开发中,项目代码量过大或通过引入很多jar导致代码量急剧增加,会出现错误: android.dex.DexIndexOverflowException: Cannot merge ...

  4. Android方法数不能超过65535

    为什么方法数不能超过65535?搬上Dalvik工程师在SF上的回答,因为在Dalvik指令集里,调用方法的invoke-kind指令中,method reference index只给了16bits ...

  5. Android方法数methods超过65536

    当Android App中的方法数超过65535时,如果往下兼容到低版本设备时,就会报编译错误: Cannot fit requested classes in a single dex file. ...

  6. 彻底解决Android 应用方法数不能超过65K的问题

    作为一名Android开发者,相信你对Android方法数不能超过65K的限制应该有所耳闻,随着应用程序功能不断的丰富,总有一天你会遇到一个异常: Conversion to Dalvik forma ...

  7. Android工程方法数超过64k,The number of method references in a .dex file cannot exceed 64K.

    最近将一个老的Eclipse项目转到Android Studio后,用gradle添加了几个依赖,项目可以make,但是一旦run就报错 Error:The number of method refe ...

  8. [Android] Android统计Apk , jar包方法数

    reference to : http://www.jianshu.com/p/61e8f803e0d1 Android在开发过程中,随着引用的库以及业务的增多,不可避免的会出现64K limit问题 ...

  9. Android应用解决65K方法数限制

    近日,Android Developers在Google+上宣布了新的Multidex支持库,为方法总数超过65K的Android应用提供了官方支持. 如果你是一名幸运的Android应用开发者,正在 ...

随机推荐

  1. linux xargs参数

    xargs是给命令传递参数的一个过滤器,也是组合多个命令的一个工具.它把一个数据流分割为一些足够小的块,以方便过滤器和命令进行处理.通常情况下,xargs从管道或者stdin中读取数据,但是它也能够从 ...

  2. Debian环境下vi设置

    下面给出一个vi编辑器的配置文件,可以放到用户目录的.vimrc文件中: "========================================================= ...

  3. Load an X509 PEM file into Windows CryptoApi

    http://stackoverflow.com/questions/1231178/load-an-x509-pem-file-into-windows-cryptoapi I discovered ...

  4. Python try/except/finally应用

    1.通过if和else处理异常 import os if os.path.exists('sketch.txt'): data = open ('sketch.txt') for each_line ...

  5. Perl 模块 Getopt::Std 和 Getopt::Long

    示例程序: getopt.pl; 1 2 3 4 5 6 7 8 #!/usr/bin/perl -w #use strict; use Getopt::Std; use vars qw($opt_a ...

  6. flash bulider 无法启动

    更新airsdk后无法启动,google下http://www.25kx.com/art/1826181有n种方法,怀疑是.metadata目录原因,可能是旧版的airsdk和新版的airsdk在.m ...

  7. Linux 下 MySQL 的彻底卸载和安装配置字符集

    前言: Linux环境下MySQL的安装和配置在网上已经有很多教程了.之所以写这篇文章是因为在配置字符集的时候找了网上的一些教程发现并不能用导致折腾了一阵子.下面的教程均是亲自实践. MySQL的彻底 ...

  8. Maven工程JAR包关联源码

    注意看上面的图,勾选了"Download Artifact Sources"和“Download Artifact JavaDoc”以后,Maven便会自动将Manven工程中的所 ...

  9. Bi-shoe and Phi-shoe(欧拉函数)

    题意: 给一些数Ai(第 i 个数),Ai这些数代表的是某个数欧拉函数的值,我们要求出数 Ni 的欧拉函数值不小于Ai.而我们要求的就是这些 Ni 这些数字的和sum,而且我们想要sum最小,求出su ...

  10. SqlServer调用外部程序实现数据同步

    首先创建两个数据库:SyncA是数据源,SyncB是对SyncA进行同步的数据库. 在SyncA和SyncB中分别创建Source表和Target表,实际业务中,两张表的结构大多不相同.     然后 ...