64K方法數限制解決辦法

隨着業務邏輯越來越多,業務模塊也越來越大,不可避免會遇到64K方法數的限制。最直觀的表現就是編譯報錯:

較早版本的編譯系統中,錯誤內容如下:

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

較新版本的編譯系統中,錯誤內容如下:

trouble writing output:
Too many field references: 131000; max is 65536.
You may try using --multi-dex option.

64K限制的原因

Android APK文件本質上是一個壓縮文件,它包含的classes.dex文件是可執行的Dalvik字節碼文件,這個.dex文件中存放的就是編譯後的Java代碼。Dalvik可執行文件規範限制了單個.dex文件最多引用的方法數是65536個。其中包含聯網Android Framework、APP引用的第三方函數庫以及APP自身的方法。

使用MultiDex解決64K限制的問題

Android 5.0之前的版本

Android 5.0之前系統使用的Dalvik虛擬機默認爲每個APK只生成一個classes.dex文件,爲了規避單個.dex文件超過64K的問題,我們拆分成多個classes.dex文件。啓動應用時先加載的classex.dex爲主dex文件,其他的爲從dex文件。Google推出一個名爲MultiDex Support Library的函數庫來避免這個問題。

Android 5.0及之後的版本

Android 5.0 之後使用ART來代替Dalvik虛擬機,ART天然支持從APK文件中加載多個.dex文件。在應用安裝期間,它會執行一個預編譯操作,並將多個單一的.dex文件編譯成一個單一的.oat文件,應用運行時區加載這個.oat文件,而不是再去一個一個加載.dex文件。

配置MultiDex

Android Gradle 插件在 Android SDK Build Tools 21.1 及更高版本的編譯工具上支持multidex作爲編譯配置的一部分,所以確保我們的Android SDK Build Tools tools已經更新至21.1或更高版本,然後再來配置應用的multidex部分。

第一步,修改app/build.grale文件,使項目能夠使用multidex:

android {
    compileSdkVersion 21
    buildToolsVersion "21.1.0"  // 這裏必須要21.1.0之後
    defaultConfig {
        minSdkVersion 14
        targetSdkVersion 21
        ...
        // Enabling multidex support.
        multiDexEnabled true
    }
    ...
}

dependencies {
  compile 'com.android.support:multidex:1.0.1'
}

第二步,修改AndroidManifest.xml文件,引用MultiDexApplication類:

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

如果用戶繼承變重寫了Application,可以將繼承的Application換成MultiDexApplication。

public class MyApplication extends MultiDexApplication {
    @Override
    public void onCreate() {
        super.onCreate();
    }
}

或者重寫attachBaseContext() 方法

@Override
 protected void attachBaseContext(Context base) {
     super.attachBaseContext(base);
     MultiDex.install(this);
}

特別注意,如果沒有實現這部分代碼,運行時會出現NoClassDefFoundError的錯誤,尤其是在依賴三方函數庫時。

在開發階段優化MultiDex的構建

multidex會加長構建應用的時間,這個必要的過程可能會拖慢你的開發進度。原因在於構建系統需要經過複雜的計算決定哪些類要包含在主.dex文件中,哪些類可以包含在從dex文件中。 爲加速構建過程,我們可以在Gradle中配置productFlavors來創建兩個flavor:一個是開發階段使用的,一個是生產階段使用的。開發階段將minSdkVersion改爲21使用ART運行時機制,這樣能加快構建速度。release時改爲合適的minSdkVersion,這樣僅在release時費時較長。

android {
    compileSdkVersion 21
    buildToolsVersion "21.1.0"  // 這裏必須要21.1.0之後
    productFlavors{
    // 配置不同的falvor
        dev {
            minSdkVersion 21     // 開發環境的minSdkVersion 
        }
        prod {
            minSdkVersion 14    // 生產環境的minSdkVersion 
        }
    }
    ...
}

dependencies {
  compile 'com.android.support:multidex:1.0.1'
}
  1. 這裏每個module對應的.dex文件不會被合併,因此避免了決定哪些類要放在主dex文件中的耗時計算。
  2. 只能在Android 5.0 設備上進行測試
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章