1. 程式人生 > >進階】之MultiDex的配置

進階】之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溢位啦~~