Android應(yīng)用解決65K方法數(shù)限制

近日,Android Developers在Google+上宣布了新的Multidex支持庫,為方法總數(shù)超過65K的Android應(yīng)用提供了官方支持。

如果你是一名幸運(yùn)的Android應(yīng)用開發(fā)者,正在開發(fā)一個(gè)前景廣闊的應(yīng)用,不斷地加入新功能、添加新的類庫,那么終有一天,你會(huì)不幸遇到這個(gè)錯(cuò)誤:

Conversion to Dalvik format failed: Unable to execute dex: method ID not in [0, 0xffff]: 65536

這個(gè)錯(cuò)誤是Android應(yīng)用的方法總數(shù)限制造成的。Android平臺(tái)的Java虛擬機(jī)Dalvik在執(zhí)行DEX格式的Java應(yīng)用程序時(shí),使用原生類型short來索引DEX文件中的方法。這意味著單個(gè)DEX文件可被引用的方法總數(shù)被限制為65536。通常APK包含一個(gè)classes.dex文件,因此Android應(yīng)用的方法總數(shù)不能超過這個(gè)數(shù)量,這包括Android框架、類庫和你自己開發(fā)的代碼。

這個(gè)問題可以通過將一個(gè)DEX文件分拆成多個(gè)DEX文件解決。Facebook介紹了為Android應(yīng)用開發(fā)的Dalvik補(bǔ)??;Android Developers博客介紹了通過自定義類加載過程的方法來解決此問題。但這些方法有些復(fù)雜而且并不優(yōu)雅。

隨著新的MultiDex支持庫發(fā)布,Google正式為解決此問題提供官方支持。構(gòu)建超過65K方法數(shù)的應(yīng)用介紹了如何使用Gradle構(gòu)建多DEX應(yīng)用。

首先使用Android SDK Manager升級(jí)到最新的Android SDK Build Tools和Android Support Library R21。然后進(jìn)行以下兩步操作:

1.修改Gradle配置文件,啟用MultiDex并包含MultiDex支持:

android { compileSdkVersion 21 buildToolsVersion "21.1.0"

defaultConfig {

...

minSdkVersion 14

targetSdkVersion 21

...

// Enabling multidex support.

multiDexEnabled true

}

...

}

dependencies { compile 'com.android.support:multidex:1.0.0' }

2.讓應(yīng)用支持多DEX文件。在MultiDexApplication JavaDoc中描述了三種可選方法:

在AndroidManifest.xml的application中聲明android.support.multidex.MultiDexApplication;

如果你已經(jīng)有自己的Application類,讓其繼承MultiDexApplication;

如果你的Application類已經(jīng)繼承自其它類,你不想/能修改它,那么可以重寫attachBaseContext()方法:

@Override

protected void attachBaseContext(Context base) {

super.attachBaseContext(base); MultiDex.install(this);

}

經(jīng)過以上步驟,你的應(yīng)用已經(jīng)可以實(shí)現(xiàn)多個(gè)DEX文件了。當(dāng)應(yīng)用構(gòu)建時(shí),構(gòu)建工具會(huì)分析哪些類必須放在第一個(gè)DEX文件,哪些類可以放在附加的DEX文件中。當(dāng)它創(chuàng)建了第一個(gè)DEX文件(classes.dex)后,如果有必要會(huì)繼續(xù)創(chuàng)建附加的DEX文件,如classes2.dex, classes3.dex。Multidex的支持類庫將被包含在應(yīng)用的第一個(gè)DEX文件中,幫助實(shí)現(xiàn)對(duì)其它DEX文件的訪問。

文中還介紹了在開發(fā)多DEX應(yīng)用時(shí),通過設(shè)置productFlavors提高開發(fā)效率以及多DEX應(yīng)用的測(cè)試方法。

Android 5.0和更高版本使用名為ART的運(yùn)行時(shí),它原生支持從APK文件加載多個(gè)DEX文件。在應(yīng)用安裝時(shí),它會(huì)執(zhí)行預(yù)編譯,掃描classes(..N).dex文件然后將其編譯成單個(gè).oat文件用于執(zhí)行。了解更多關(guān)于ART的信息。

雖然Google解決了應(yīng)用總方法數(shù)限制的問題,但并不意味著開發(fā)者可以任意擴(kuò)大項(xiàng)目規(guī)模。Multidex仍有一些限制:

DEX文件安裝到設(shè)備的過程非常復(fù)雜,如果第二個(gè)DEX文件太大,可能導(dǎo)致應(yīng)用無響應(yīng)。此時(shí)應(yīng)該使用ProGuard減小DEX文件的大小。

由于Dalvik linearAlloc的Bug,應(yīng)用可能無法在Android 4.0之前的版本啟動(dòng),如果你的應(yīng)用要支持這些版本就要多執(zhí)行測(cè)試。

同樣因?yàn)镈alvik linearAlloc的限制,如果請(qǐng)求大量內(nèi)存可能導(dǎo)致崩潰。Dalvik linearAlloc是一個(gè)固定大小的緩沖區(qū)。在應(yīng)用的安裝過程中,系統(tǒng)會(huì)運(yùn)行一個(gè)名為dexopt的程序?yàn)樵搼?yīng)用在當(dāng)前機(jī)型中運(yùn)行做準(zhǔn)備。dexopt使用LinearAlloc來存儲(chǔ)應(yīng)用的方法信息。Android 2.2和2.3的緩沖區(qū)只有5MB,Android 4.x提高到了8MB或16MB。當(dāng)方法數(shù)量過多導(dǎo)致超出緩沖區(qū)大小時(shí),會(huì)造成dexopt崩潰。

Multidex構(gòu)建工具還不支持指定哪些類必須包含在首個(gè)DEX文件中,因此可能會(huì)導(dǎo)致某些類庫(例如某個(gè)類庫需要從原生代碼訪問Java代碼)無法使用。

避免應(yīng)用過大、方法過多仍然是Android開發(fā)者要注意的問題。Mihai Parparita的開源項(xiàng)目dex-method-counts可以用于統(tǒng)計(jì)APK中每個(gè)包的方法數(shù)量。

通常開發(fā)者自己的代碼很難達(dá)到這樣的方法數(shù)量限制,但隨著第三方類庫的加入,方法數(shù)就會(huì)迅速膨脹。因此選擇合適的類庫對(duì)Android開發(fā)者來說尤為重要。

開發(fā)者應(yīng)該避免使用Google Guava這樣的類庫,它包含了13000多個(gè)方法。盡量使用專為移動(dòng)應(yīng)用設(shè)計(jì)的Lite/Android版本類庫,或者使用小類庫替換大類庫,例如用Google-gson替換Jackson JSON。而對(duì)于Google Protocol Buffers這樣的數(shù)據(jù)交換格式,其標(biāo)準(zhǔn)實(shí)現(xiàn)會(huì)自動(dòng)生成大量的方法。采用Square Wire的實(shí)現(xiàn)則可以很好地解決此問題。

------轉(zhuǎn)自博客園

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容