Android 分Dex (MultiDex)


需要分Dex的理由想必大家都知道了.正是在ART以前的Android系統中,Dex文件對於方法索引是用一個short類型的數據來存放的.而short的最大值是65535,因此當項目足夠大包含方法數目足夠多超過了65535(包括引用的外部Lib里面的所有方法),當運行App,就會得到如下的錯誤提示.

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

 

這個致命嚴重的Bug出現后,Android官方就寫了一篇著名的Blog(這篇文章我讀了五六遍,甚至連作者的Google+的照片我都看了兩三次,我還是沒有完全搞明白怎么Walkaround這個嚴重的問題).

再后來,慢慢發展,有很多能人異士發揮自己的創造力,寫了開源的Lib放在GitHub上分享給其他Android開發者們使用.HelloMultiDex, Secondary-Dex-Gradle等等.

但是解鈴還須系鈴人,這種系統性的嚴重致命Bug,當然還是Android官方給出解決方案最讓人放心.終於,我們還是等到了你,MultiDex Offical Solution.

我推薦官方文檔這篇GitHub的文章一起看會有更好的了解,少走彎路.

 

下面說一說使用的步驟:

1. 修改Gradle,導入'com.android.support:multidex:1.0.0',打開multiDexEnabled;

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.修改Application.兩種方法:

   1) 直接把Application替換成MultiDexApplication

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.android.multidex.myapplication">
    <application ... android:name="android.support.multidex.MultiDexApplication"> ... </application>
</manifest>

  2) 在原來的Application中修改調用MultiDex.install(this);

public class HelloMultiDexApplication extends Application { @Override public void onCreate() { super.onCreate(); } @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); MultiDex.install(this); } }

 

到這里其實MultiDex的配置已經完成了.

但是,實際上下面介紹的3個問題也非常值得我們關注.

1. 一些在二級Dex加載之前,可能會被調用到的類(比如靜態變量的類),需要放在主Dex中.否則會ClassNotFoundError.

    通過修改Gradle,可以顯式的把一些類放在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/<filename>".toString() } }

    上面是修改后的Gradle,其中<filename>是一個文本文件的文件名,存放在和這個Gradle腳本同一級的文件目錄下.

    而這個文本文件的內容如下.實際就是把需要放在Main Dex的類羅列出來.

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

 

2. 如果用使用其他Lib,要保證這些Lib沒有被preDex,否則可能會拋出下面的異常

UNEXPECTED TOP-LEVEL EXCEPTION: com.android.dex.DexException: Library dex files are not supported in multi-dex mode at com.android.dx.command.dexer.Main.runMultiDex(Main.java:337) at com.android.dx.command.dexer.Main.run(Main.java:243) at com.android.dx.command.dexer.Main.main(Main.java:214) at com.android.dx.command.Main.main(Main.java:106)

   遇到這個異常,需要在Gradle中修改,讓它不要對Lib做preDexing

android { // ...
 dexOptions { preDexLibraries = false } }

 

3. 如果每次都打開MultiDex編譯版本的話,會比平常用更多的時間(這個也容易理解,畢竟做了不少事情)

    Android的官方文檔也給了我們一個小小的建議,利用Gradle建立兩個Flavor.一個minSdkVersion設置成21,這是用了ART支持的Dex格式,避免了MultiDex的開銷.而另外一個Flavor就是原本支持的最小sdkVersion.平時開發時候調試程序,就用前者的Flavor,發布版本打包就用后者的Flavor.

android { productFlavors { // Define separate dev and prod product flavors.
 dev { // dev utilizes minSDKVersion = 21 to allow the Android gradle plugin // to pre-dex each module and produce an APK that can be tested on // Android Lollipop without time consuming dex merging processes.
            minSdkVersion 21 } prod { // The actual minSdkVersion for the application.
            minSdkVersion 14 } } ... buildTypes { release { runProguard true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { compile 'com.android.support:multidex:1.0.0' }

 

有了Android官方的支持后,MultiDex比最原始的解決方案簡單多了.媽媽再也不用擔心我們要分Dex啦!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM