詭異的NoClassDefFoundError錯誤——也可能是65536引起的

一 場景

症狀一

本來好好的App,在引入了某個第三方庫之後,忽然就開始報錯了:

Caused by: java.lang.ClassNotFoundException: Didn’t find class “com.yourapp.XXX”

ClassNotFoundException——這是個很常見的錯誤啊,加載某些類的時候沒找到嘛!
然而這次的詭異之處在於,這個com.yourapp.XXX明明就在那裏,Android系統你爲啥找不到呢,難道見鬼了麼。

症狀二

經過測試發現,只有Android2.x、Android4.x的機型會出現這種情況,Android5.x/6.x則能順利通過

二 原因呢

如果你經過反覆的Clean Project、 Rebuild Project、把某個包衝刪除重新加入、重新安裝app…… 還是沒有找到原因的話,那很有可能就是因爲那個著名的the 64K Reference Limit問題了。

名詞解釋: Android application (APK) files contain executable bytecode files in the form of Dalvik Executable (DEX) files, which contain the compiled code used to run your app. The Dalvik Executable specification limits the total number of methods that can be referenced within a single DEX file to 65,536—including Android framework methods, library methods, and methods in your own code. In the context of computer science, the term Kilo, K, denotes 1024 (or 2^10). Because 65,536 is equal to 64 X 1024, this limit is referred to as the ’64K reference limit

用中國話說:就是在Android中,由於某些原因,會導致單個Dex文件中最多隻能容納65536(64k)個方法,如果app中的方法數量多於65536個,就會導致這種錯誤。

千萬不要覺得65536很多啊

一般在項目中,我們自己收寫的代碼只是很小一部分,大部分代碼是在你引用的第三方輪子中啊,比如這些最常用的:

Name | Method Count ——— | ————- Gson 2.3 | 1,243 Jackson 3.4.3 | 6,731 Android Support V4 21 | 8,078
所以如果用的輪子多了,分分鐘就會到了64k大限了。

這個問題有時會有其他的日誌:

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

或者:

Too many field references: 131000; max is 65536. You may try using –multi-dex option.

如果是這兩個報錯,問題就明顯多了,一看到65536這個神奇的數字就可以定位到這個病因了。

三 解決方案

知道病因之後,治病就簡單了

精簡代碼,去除冗餘

  • 經常清理一些過期不要的代碼是個好習慣
  • 如果有功能類似的輪子也可以只保留一個,比如Gson/Jackson、Fresco/Glide、EventBus/Otto

開啓ProGuard

自動去除一些未使用的代碼,不過要注意很多輪子中的ProGuard配置,不然可能會導致動態加載的一些方法失效

終極方案MultiDex

名詞解釋:MultiDex allows you to use multiple DEX files contained within one APK. With a few steps, your classes will split automatically into several DEX files (classes.dex, classes2.dex, classes3.dex, etc) in case you reach the method index limit. Information on how to integrate MultiDex into your application will follow.

用中國話說,MultiDex就是一項技術,可以讓一個apk中包含多個dex文件,每個dex文件中都不超過64k個方法,這樣就OK啦

開啓MultiDex方法

如果Android 5.0(API 21)以上會自動支持MultiDex,當然目前(2016年)我們的app可能不能只支持到API21了,所以還是需要在項目中配置的,需要如下三步:

1 在build.grade中配置defaultConfig:

defaultConfig {
...
// Enabling multidex support.
multiDexEnabled true
}

2 在build.grade中配置dependencies:

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

3 使用MultiDexApplication取代Application:

① 如果沒有自定義Application,那麼在AndroidManifest.xml中指定MultiDexApplication即可
② 如果有自定義的MyApplaction extends Application,那麼改成MyApplaction extends MultiDexApplication
③ 如果有自定義的MyApplaction繼承了一個不能修改的XApplication,那麼覆蓋attachBaseContext()方法,在其中調用一下MultiDex.install(this)也可以。

四 鏈接

ProGuard: https://developer.android.com/studio/build/shrink-code.html
Multidex官方指南: https://developer.android.com/studio/build/multidex.html

轉自:http://www.apkbus.com/blog-705730-62519.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章