64k的各種異常
當你的應用程式和庫引用達到一定規模,你遇到建構錯誤顯示你的應用已經達到了一個Android應用程式建構體系結構的限制。早期版本的建構系統報告這個錯誤如下:
Conversion to Dalvik format failed:
Unable to execute dex: method ID not in [0, 0xffff]: 65536
或者
UNEXPECTED TOP-LEVEL EXCEPTION:
java.lang.IllegalArgumentException: method ID not in [0, 0xffff]: 65536
at com.android.dx.merge.DexMerger$6.updateIndex(DexMerger.java:501)
at com.android.dx.merge.DexMerger$IdMerger.mergeSorted(DexMerger.java:282)
at com.android.dx.merge.DexMerger.mergeMethodIds(DexMerger.java:490)
at com.android.dx.merge.DexMerger.mergeDexes(DexMerger.java:167)
at com.android.dx.merge.DexMerger.merge(DexMerger.java:188)
at com.android.dx.command.dexer.Main.mergeLibraryDexBuffers(Main.java:439)
at com.android.dx.command.dexer.Main.runMonoDex(Main.java:287)
at com.android.dx.command.dexer.Main.run(Main.java:230)
at com.android.dx.command.dexer.Main.main(Main.java:199)
at com.android.dx.command.Main.main(Main.java:103)
最新版本的Android建構系統顯示一個不同的錯誤,但是是同樣一個問題:
trouble writing output:
Too many field references: 131000; max is 65536.
You may try using --multi-dex option.
或者
Error:The number of method references in a .dex file cannot exceed 64K.
上面的錯誤顯示一個共同的數字:65536。這個數字是重要的,它代表了引用的總數,可以在單個調用的代碼Dalvik可執行(Dex)位元組碼檔案。如果你的Android應用發生這個錯誤,恭喜你,你的代碼已經達到了一定的量!本文解釋了如何解決這個限制并繼續建構應用程式。
關于64 k引用限制
Android應用程式(APK)在Dalvik可執行檔案的形式包含可執行的位元組碼檔案(DEX)檔案,其中包含已編譯的代碼來運作你的應用程式。Dalvik可執行規格限制一個Dex檔案包含65536個方法:包括Android架構方法、Library方法的總數、和你自己的代碼方法總數。因為65536等于64×1024,這一限制被稱為“64k引用限制”。
這個極限就要求我們配置應用程式的建構過程,需要生成多個DEX檔案,是以稱為multidex 配置。
分析原因與注意事項
解決方法分Android 5.0及以上系統和5.0以下系統怎麼做。客官們不要着急,先看我一個個分析原因,畢竟我要裝下逼哈哈。
一、Android 5.0以下的版本
Android 5.0(API leve 21)之前的系統使用Dalvik執行應用程式代碼。預設情況下,Dalvik限制一個apk隻有一個Dex檔案。為了繞過這個限制, 我們可以使用multidex support library,它成為我們APK的主要DEX檔案的一部分,負責管理我們APK通路其他DEX檔案和代碼。
注意: 如果咱的項目minSdkVersion是20或更低,運作到Android 4.4(API leve 20)或者更低版本的裝置上時需要禁用AndroidStudio的即時運作
二、Android 5.0和更高版本
Android 5.0(API leve 21)和更高的系統使用runtime是ART ,原生支援從應用的apk檔案加載多個DEX檔案。ART在安裝應用時預編譯應用程式,會掃描多個classes(..N).dex檔案編譯成一個.oat的檔案。更多Android5.0 runtime的更多資訊,請參見即時運作-instant-run。
注意: 如果你使用即時運作 , AndroidStudio自動配置你的應用程式,你應用程式的minSdkVersion應該設定為21或更高。因為即時隻工作在你APP的Debug版本,你任然需要配置你的release版本建構時用multidex避免64k的限制。
盡量避免64k限制
在配置我們的App啟用64k或者更多方法引用之前,我們可以減少應用代碼内的排程總數,包括我們自身應用的方法和第三方的庫,下面的幾個政策或許可以幫到你:
•檢查你的APP的直接和間接的過度依賴關系:有時候我們用到某個Libaray的某幾個方法或者功能時這個庫非常大,減少這種依賴可能對與避免64k的問題非常有效。
•在正式打包建構的時候,使用代碼混淆器ProGuard混淆移除未使用的代碼,也就是不把沒有使用的代碼打包到我們的apk中。
使用上面的方法可以幫助我們避免在應用程式中生成太多無用的方法和減小我們apk的大小,這對于用自己伺服器做app更新更新的同學是非常有幫助的。
這裡給大家推薦下任玉剛同學的插件式開發架構:https://github.com/singwhatiwanna/dynamic-load-apk,共同參與開發者:田嘯,宋思宇。
解決64k問題
在Android SDK Build Tools 21.1或者更高版本的build工具中用Android plugin gradle。確定你更新Android SDK build tools和Android support到最新版本,然後用multidex配置應用程式。我們必須要做兩步。
第一步,修改主module的build.gradle檔案
在gradle中依賴multidex,并啟用multiDexEnable:
android {
compileSdkVersion 21
buildToolsVersion
defaultConfig {
...
minSdkVersion 14
targetSdkVersion 21
...
// Enabling multidex support.
multiDexEnabled true
}
...
}
dependencies {
compile 'com.android.support:multidex:1.0.1'
}
第二步,繼承android.support.multidex.MultiDexApplication類
兩種情況
第一種情況,如果我們的APP沒有重寫過Application類,我們直接繼承MultiDexApplication,然後在manifest.xml中注冊Application即可。
第二種情況,如果我們已經重寫過Application類,重寫attachBaseContext(Context)方法,并調用MultiDex.install(this);即可:
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
因為我翻過MultiDexApplication的源碼了,裡面就是重寫了這個方法而已哈哈:
public class MultiDexApplication extends Application {
public MultiDexApplication() {
}
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
}
注冊Application
package=>
...
android:name="剛才重寫的Application全類名">
...
multidex庫的一些限制因素
•DEX檔案安裝到裝置的過程非常複雜,如果第二個DEX檔案太大,可能導緻應用無響應。此時應該使用ProGuard減小DEX檔案的大小。
•由于Dalvik linearAlloc的Bug,應用可能無法在Android 4.0之前的版本啟動,如果你的應用要支援這些版本就要多執行測試。
•同樣因為Dalvik linearAlloc的限制,如果請求大量記憶體可能導緻崩潰。Dalvik linearAlloc是一個固定大小的緩沖區。在應用的安裝過程中,系統會運作一個名為dexopt的程式為該應用在目前機型中運作做準備。dexopt使用LinearAlloc來存儲應用的方法資訊。Android 2.2和2.3的緩沖區隻有5MB,Android 4.x提高到了8MB或16MB。當方法數量過多導緻超出緩沖區大小時,會造成dexopt崩潰。
•Multidex建構工具還不支援指定哪些類必須包含在首個DEX檔案中,是以可能會導緻某些類庫(例如某個類庫需要從原生代碼通路Java代碼)無法使用。
使用了multidex後的建構優化
一、是以如果應用中包含lirary工程,可能會發生如下錯誤:
UNEXPECTED TOP-LEVEL EXCEPTION:
com.android.dex.DexException: Library dex files are not supported in multi-dex mode
這個時候我們需要禁用預編譯:
android {
...
dexOptions {
preDexLibraries = false
}
...
}
二、如果在運作的時候遇到如下錯誤:
UNEXPECTED TOP-LEVEL ERROR:
java.lang.OutOfMemoryError: Java heap space
我們需要加大java堆記憶體大小:
maxProcessCount 4 // this is the default value
javaMaxHeapSize "2g"
三、提升運作速度
在Android leve 21或者更高SDK版本。使用ART-supported格式生成multidex輸出更快,為我們節省時間,是以我們不必在調試的使用也相容到5.0以下,是以我們配置最低版本的時候做個如下相容:
android {
productFlavors {
// 自定義偏好設定.
dev {
// 在Android leve 21或更高版本編譯更快
minSdkVersion 21
}
prod {
// 真正的生産環境.
minSdkVersion 14
}
}
...
}
dependencies {
compile 'com.android.support:multidex:1.0.1'
}
Android plugin Gradle版本低于1.1怎麼辦
你需要添加 以下依賴 multidex-instrumentation :
dependencies {
androidTestCompile('com.android.support:multidex-instrumentation:1.0.1') {
exclude group: 'com.android.support', module: 'multidex'
}
}
以上就是本文的全部内容,希望對大家的學習有所幫助,也希望大家多多支援腳本之家。