這里給大家推薦一個Android源碼網(wǎng)站:http://androidxref.com/(無需翻墻)
前言
65536是什么樣的數(shù)楞黄?2的16次方或者說64KB
下邊這個error是不是很熟悉
較高版本的Android構(gòu)建系統(tǒng)下的提示(Android 7.0及以下):
Conversion to Dalvik format failed:
Unable to execute dex: method ID not in [0, 0xffff]: 65536
較高版本的Android構(gòu)建系統(tǒng)的報錯信息(Android 8.0)
trouble writing output:
Too many field references: 131000; max is 65536.
You may try using --multi-dex option.
注意:構(gòu)建時期發(fā)生的錯誤哦
為什么會出現(xiàn)64K的限制呢侦铜?
一般排查問題我們需要從問題本身入手,那么log是最重要的信息浇冰。
在構(gòu)建流程中出現(xiàn)這種問題殊霞,根據(jù)提示我們大概明白方法數(shù)過大畸悬,而這些方法是存在于編譯后的.class
文件中的,而.class
最后要存在于dex文件中灾部。
那么如此分析的話康铭,問題應(yīng)該存在于dex的打包流程當中,這個需要以后深入了解一下赌髓。
根據(jù)前人的一些分析从藤,我們來看看MemberIdsSection文件。代碼不多春弥,如下:
1 /*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.dx.dex.file;
18
19import com.android.dex.DexFormat;
20import com.android.dex.DexIndexOverflowException;
21
22import java.util.Formatter;
23import java.util.Map;
24import java.util.TreeMap;
25import java.util.concurrent.atomic.AtomicInteger;
26
27/**
28 * Member (field or method) refs list section of a {@code .dex} file.
29 */
30public abstract class MemberIdsSection extends UniformItemSection {
31
32 /**
33 * Constructs an instance. The file offset is initially unknown.
34 *
35 * @param name {@code null-ok;} the name of this instance, for annotation
36 * purposes
37 * @param file {@code non-null;} file that this instance is part of
38 */
39 public MemberIdsSection(String name, DexFile file) {
40 super(name, file, 4);
41 }
42
43 /** {@inheritDoc} */
44 @Override
45 protected void orderItems() {
46 int idx = 0;
47
48 if (items().size() > DexFormat.MAX_MEMBER_IDX + 1) {
49 throw new DexIndexOverflowException(getTooManyMembersMessage());
50 }
51
52 for (Object i : items()) {
53 ((MemberIdItem) i).setIndex(idx);
54 idx++;
55 }
56 }
57
58 private String getTooManyMembersMessage() {
59 Map<String, AtomicInteger> membersByPackage = new TreeMap<String, AtomicInteger>();
60 for (Object member : items()) {
61 String packageName = ((MemberIdItem) member).getDefiningClass().getPackageName();
62 AtomicInteger count = membersByPackage.get(packageName);
63 if (count == null) {
64 count = new AtomicInteger();
65 membersByPackage.put(packageName, count);
66 }
67 count.incrementAndGet();
68 }
69
70 Formatter formatter = new Formatter();
71 try {
72 String memberType = this instanceof MethodIdsSection ? "method" : "field";
73 formatter.format("Too many %1$s references to fit in one dex file: %2$d; max is %3$d.%n" +
74 "You may try using multi-dex. If multi-dex is enabled then the list of " +
75 "classes for the main dex list is too large.%n" +
76 "References by package:",
77 memberType, items().size(), DexFormat.MAX_MEMBER_IDX + 1);
78 for (Map.Entry<String, AtomicInteger> entry : membersByPackage.entrySet()) {
79 formatter.format("%n%6d %s", entry.getValue().get(), entry.getKey());
80 }
81 return formatter.toString();
82 } finally {
83 formatter.close();
84 }
85 }
86
87}
在48行到49中呛哟,我們看到如下可能拋出異常的情況
if (items().size() > DexFormat.MAX_MEMBER_IDX + 1) {
throw new DexIndexOverflowException(getTooManyMembersMessage());
}
getTooManyMembersMessage()函數(shù)內(nèi)(72行到77行)有如下異常信息字符串構(gòu)造
String memberType = this instanceof MethodIdsSection ? "method" : "field";
formatter.format("Too many %1$s references to fit in one dex file: %2$d; max is %3$d.%n" +
"You may try using multi-dex. If multi-dex is enabled then the list of " +
"classes for the main dex list is too large.%n" +
"References by package:",
memberType, items().size(), DexFormat.MAX_MEMBER_IDX + 1);
同時我們還要注意DexFormat
類叠荠,
/**
* Maximum addressable field or method index.
* The largest addressable member is 0xffff, in the "instruction formats" spec as field@CCCC or
* meth@CCCC.
*/
public static final int MAX_MEMBER_IDX = 0xFFFF;
根據(jù)注釋,我們來到Dalvik 字節(jié)碼匿沛,根據(jù)表格中的解釋如下圖:
可以看到類型索引(16 位),由此可以知道榛鼎,無論是方法數(shù)還是字段數(shù)都不能超過65536逃呼,這也就是為什么在構(gòu)建流程中出現(xiàn)65536的報錯信息。
由此可以得出結(jié)論:
單個dex的方法或者字段數(shù)量不能超過65536
如何避免64K問題者娱?涉及到dex分包的知識抡笼,同時也是涉及到APK瘦身優(yōu)化等問題。
很多問題都需要我們?nèi)ブ泵婊器ⅲ徊讲饺ソ鉀Q推姻。