一、什么是MultiDex
隨着時代的進步,人們對手機 APP 的需求越來越大,越來越苛刻,很多APP都變得很大,再加上APP都不可避免的需要導入一些框架、第三方類庫等等,就更加大了項目的整體文件體系。如果文件太多,系統可能會報如下錯誤:
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基於JAVA語言,JAVA語言在編譯之后都會生成字節碼文件.class,在Android中,這些文件都被存儲在一個.dex文件中。由於DEX文件的格式限制,其中的Method、Field、Class的個數都不能超過short類型的最大值65535,如果超過了這個值,就會報上面的錯誤。
為了解決這個問題,Google - Android在API 21的時候為廣大程序員提供了一個通用的解決方案,就是今天要說的MultiDex方案。這個方案讓Android系統可以在原始的DEX文件存滿之后自動生成一個新的DEX文件,從而解決這個DEX溢滿的問題。
二、MultiDex的配置
MultiDex的配置主要是在Gradle文件中進行的,但是不僅需要配置Module中的Gradle文件,還需要配置項目根目錄下的Gradle文件。
首先,我們先來配置Module中的Gradle文件,文件中的代碼如下:
apply plugin: 'com.android.application' android { // productFlavors是為了避免每次運行都把DEX重新加載一遍而設置的兩套運行配置 productFlavors { dev { minSdkVersion 21 } prod { minSdkVersion 14 } } compileSdkVersion 24 buildToolsVersion "24.0.2" defaultConfig { applicationId "com.example.itgungnir.testmultidex" minSdkVersion 11 targetSdkVersion 24 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" // 設置MultiDex可用 multiDexEnabled true } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } // 保證其他的lib沒有被preDex dexOptions { preDexLibraries = false } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) compile 'com.android.support:appcompat-v7:24.2.1' testCompile 'junit:junit:4.12' // MultiDex的依賴 compile 'com.android.support:multidex:1.0.0' }
從代碼中可以看到,這里主要做了以下更改:
- 在android代碼塊中加入了productFlavors和dexOptions兩個子代碼塊;
- 添加了MultiDex的依賴包;
- 在defaultConfig代碼塊中設置開啟了MultiDex。
配置完Module下的Gradle文件,接下來配置Project下的Gradle文件。文件中的代碼如下:
buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:2.2.0' } } allprojects { repositories { jcenter() } } task clean(type: Delete) { delete rootProject.buildDir } // 保證dex_files文件中指定的文件都加載到Main Dex中 afterEvaluate { tasks.matching { it.name.startsWith('dex') }.each { dx -> if (dx.additionalParameters == null) { dx.additionalParameters = [] } dx.additionalParameters += '--multi-dex' dx.additionalParameters += "--main-dex-list=$projectDir/dex_files".toString() } }
可以看到,這里主要添加了afterEvaluate代碼塊,最后一行中的dex_files是一個.txt文件,其中存放着想要默認加載到MainDex中的所有文件。這個dex_files文件是和這個Gradle文件在同一級目錄下,以下是dex_files.txt文件中的代碼(大家可以根據需要添加):
android/support/multidex/BuildConfig/class android/support/multidex/MultiDex$V14/class android/support/multidex/MultiDex$V19/class android/support/multidex/MultiDex$V4/class android/support/multidex/MultiDex/class android/support/multidex/MultiDexApplication/class android/support/multidex/MultiDexExtractor$1/class android/support/multidex/MultiDexExtractor/class android/support/multidex/ZipUtil$CentralDirectory/class android/support/multidex/ZipUtil/class
最后,需要在項目的Application文件中注入MultiDex,代碼如下:
public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); } @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); // 將MultiDex注入到項目中 MultiDex.install(this); } }
別忘了在Manifest文件中注冊Application:
android:name=".MyApplication"
到此為止,MultiDex就已經配置好了,媽媽再也不用擔心我的項目dex溢出啦~~