1. 程式人生 > >Android 65K問題之Multidex原理分析及NoClassDefFoundError的解決方法

Android 65K問題之Multidex原理分析及NoClassDefFoundError的解決方法

bottom mini ati ... types auto weight right for


Android 65K問題相信困惑了不少人,盡管AS的出來能夠通過分dex高速解決65K問題,可是同一時候也easy由於某些代碼沒有打包到MainDex裏引起NoClassDefFoundError

隨著5.0的推出,Android也放出了Multidex Support Library來解決問題。

Multidex Support Library能夠直接分包處理65K問題。而且不會發生NoClassDefFoundError的情況。
1.使用的話。首先加入依賴庫: //分包multiDexEnabled必須加入該依賴
compile ‘com.android.support:multidex:1.0.1‘



2.另外開啟Multidex開關: buildTypes {
release {
minifyEnabled false
//分包
multiDexEnabled true
proguardFiles getDefaultProguardFile(‘proguard-android.txt‘), ‘proguard-rules.pro‘
}
}

3.這時候執行的話可能會報java堆內存錯誤,因此最好加入上: dexOptions {
javaMaxHeapSize
"4g"
incremental true
}

4.假設你有自己的Application,則改動一下Application使其繼承MultiDexApplication: public class MyApplication extends MultiDexApplication {

...
}

假設你的Application非常不幸已經繼承了其它Application導致無法繼承MultiDexApplication的話。那也是能夠是,僅僅須要復寫該方法並加上該代碼: @Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(base);
}
這時候你就能夠跑了,詳細能夠看官方文檔,畢竟官方文檔裏面寫得很清楚。


以下我們主要來說下Multidex的實現方法,以下部分來源:http://blog.waynell.com/2015/04/19/android-multidex/ 的分析。
Multidex的實現原理
Multidex的實現原理是將class編譯進不同的classes.dex文件裏。普通情況下。一個APK文件裏僅僅包括了一個classes.dex文件。

分包之後就存在一個主的classes.dex,多個副的classes2.dex,classes3.dex… 在要啟動程序時,Android會先去載入主的classes.dex。然後在程序啟動後再去載入其他副的dex。那哪些class應該被編譯到主的classes.dex中呢?
先來看下Multidex的編譯過程,它由三個不同的gradle task組成:
1
collect{variant}MultiDexComponents task

這個task會讀取項目的AndroidManifest.xml文件裏註冊的application、Activity、service、receiver、provider、instrumentation相關類,並將其class文件路徑寫到文件buidl/intermediates/multi-dex/${variant.dirName}/manifest_keep.txt

1
shrink{variant}MultiDexComponents task

這個task會調用ProGuard並依據上一步生成的manifest_keep.txt文件內容去壓縮class,剔除沒實用到的class。生成一個精簡的jar包buidl/intermediates/multi-dex/${variant.dirName}/componentClasses.jar

1
create{variant}MainDexClassList task

這個task會依據上一步生成的componentClasses.jar去尋找這裏面的各個class文字中依賴的class,比方一個class中有一成員變量X。那麽X就是依賴的class,componentClasses.jar中全部的class和依賴的class路徑都會被寫入到文件buidl/intermediates/multi-dex/${variant.dirName}/maindexlist.txt中,這個文件裏的類都會被編譯進主的classes.dex中去。(詳情能夠查看ClassReferenceListBuilder的實現源代碼)

NoClassDefFoundError

Multidex固然是好的,不用再為方法數超過65536而苦惱了。

可是有時往往會帶來意想不到的bug。比方NoClassDefFoundError。之前我就在項目中遇到了這個問題。一啟動程序就crash了,看log是因為某個類找不到引起的。


通過上面的分析,我們已經得知Multidex的原理了,所以要解決一啟動程序就NoClassDefFoundError的問題僅僅須要確定該類是否正確被編譯到主classes.dex中去了。假設沒有被編進去的話,僅僅要改動下maindexlist.txt文件。把這個類加入進去就可以。因為maindexlist.txt這個文件是每次編譯時自己主動生成的,手動去改動它是無用的。所以我們能夠在gradle編譯中新加入一個task,在create{variant}MainDexClassList這個task完畢之後再去改動maindexlist.txt文件加入丟失的class。

Android 65K問題之Multidex原理分析及NoClassDefFoundError的解決方法