目錄: - 一、前言
- 二、產生原因
- 三、MultiDex的簡要原理
- 四、MultiDex的使用
- 一、前言
- 二、產生原因
- 三、MultiDex的簡要原理
- 四、MultiDex的使用
一、前言
首先說一下我遇到的情況,最近接手了一個項目是在已有的項目里進行更新添加一些功能,然后該項目導了N多的包,在我使用Android Studio的run”App”直接安裝到手機上運行是正常的,然后正式打包安裝后就崩潰了,當時覺得很奇怪,然后一看日志:
trouble writing output:?
Too many field references: 131000; max is 65536.?
You may try using --multi-dex option.
沒辦法只好查資料:?
Note: While using Instant Run, Android Studio automatically configures your app for multidex when your app's minSdkVersion is set to 21 or higher. Because Instant Run only works with the debug version of your app, you still need to configure your release build for multidex to avoid the 64K limit.
大概意思就是:
如果使用Instant Run,當app的minSdkVersion大于或等于21時,Android Studio會自動配置支持multidex,但是僅debug版本有效,release版仍然需要配置multidex來突破64K限制。
二、產生原因
在Android系統中,一個App的所有代碼都在一個Dex文件里面。Dex是一個類似Jar的存儲了多有Java編譯字節碼的歸檔文件。因為Android系統使用Dalvik虛擬機,所以需要把使用Java Compiler編譯之后的class文件轉換成Dalvik能夠執行的class文件。這里需要強調的是,Dex和Jar一樣是一個歸檔文件,里面仍然是Java代碼對應的字節碼文件。當Android系統啟動一個應用的時候,有一步是對Dex進行優化,這個過程有一個專門的工具來處理,叫DexOpt。DexOpt的執行過程是在第一次加載Dex文件的時候執行的。這個過程會生成一個ODEX文件,即Optimised Dex。執行ODex的效率會比直接執行Dex文件的效率要高很多。但是在早期的Android系統中,DexOpt有一個問題,也就是這篇文章想要說明并解決的問題。DexOpt會把每一個類的方法id檢索起來,存在一個鏈表結構里面。但是這個鏈表的長度是用一個short類型來保存的,導致了方法id的數目不能夠超過65536個。當一個項目足夠大的時候,顯然這個方法數的上限是不夠的。盡管在新版本的Android系統中,DexOpt修復了這個問題,但是我們仍然需要對低版本的Android系統做兼容。
為了解決方法數超限的問題,需要將該dex文件拆成兩個或多個,為此谷歌官方推出了multidex兼容包,配合AndroidStudio實現了一個APK包含多個dex的功能。
三、MultiDex的簡要原理?
我們以APK中有兩個dex文件為例,第二個dex文件為classes2.dex。?
兼容包在Applicaion實例化之后,會檢查系統版本是否支持 multidex,classes2.dex是否需要安裝。?
如果需要安裝則會從APK中解壓出classes2.dex并將其拷貝到應用的沙盒目錄下。?
通過反射將classes2.dex注入到當前的classloader中。?
下面引入一下官方的文檔:?
https://developer.android.com/tools/building/multidex.html#about
四、MultiDex的使用
1、在Gradle中配置使用Multidex
由于Android的Gradle插件在Android Build Tool 21.1開始支持使用multidex,所以我們需要使用Android Build Tools 21.1及以上版本,修改app目錄下的build.gradle文件,有兩點需要修改。
(1)在defaultConfig中添加multiDexEnabled true這個配置項。?
(2)在dependencies中添加multidex的依賴:?
compile ‘com.android.support:multidex:1.0.1’
2、在Gradle中配置好之后,我們還需要在代碼中加入支持multidex的功能,有三種方案可選
方案一:在manifest文件中指定Application為MultiDexApplication,如下:
方案二:寫一個Application類并繼承MultiDexApplication,并在AndroidManifest.xml的application標簽中進行注冊(在application標簽中增加name屬性,并添加自己的Application類名即可),如果不是想重寫MultiDexApplication中一些方法的話,還是方案一更方便些。如下:
注冊如下:
方案三:如果不想按方案二繼承,我們可以重寫Application的attachBaseContext方法,注意,這個方法比onCreate方法先執行。具體方法是創建一個新類,繼承Application,然后重寫attachBaseContext方法,并在AndroidManifest.xml的application標簽中進行注冊(與方案二注冊相同)如下:
對于在AndroidManifest.xml中注冊,與方案二的注冊相同。