1. 程式人生 > >Android DEX方法超過64K和gradle編譯OOM解決方案

Android DEX方法超過64K和gradle編譯OOM解決方案

首先貼上報錯資訊:Error:Execution failed for task ':app:transformClassesWithDexForDebug'.> com.android.build.api.transform.TransformException: com.android.ide.common.process.ProcessException: org.gradle.process.internal.ExecException: Process 'command 'C:\Program Files\Java\jdk1.8.0_60\bin\java.exe'' finished with non-zero exit value 2

使用Android studio開發的小夥伴肯定都會遇到過這個錯誤,出現這個錯誤一般情況是專案中存在衝突了,我一看到這個錯誤的時候好淡定,因為本人之前遇到過,就是lib裡面存在有重複的jar庫檔案,於是第一時間就去檢查自己的lib下是否存在有重複的jar檔案,於是檢查半天發現並沒有重複的jar,於是檢視build.gradle檔案dependencies是否有重複的,可是還是沒發現有重複的.到網上各種百度,各種谷歌,大多數會說是載入有重複的jar檔案,或者是jdk版本的問題(其實出現這個問題一般跟jdk版本是沒多大關係的).

一直尋找編譯不過的原因,於是我把程式碼恢復到之前的版本,發現專案可以編譯通過毫無問題,只要加入新程式碼就出現這個問題,於是我有重複地檢查我的程式碼是否有什麼問題,檢查了N次依然不知道是什麼原因,後面我嘗試著刪除最新加入的一個JavaBean 類,可以編譯通過.感覺到問題好奇怪,於是我就想是不是專案中dex方法超過了64K的上限,通過多次反覆的驗證,我最終確定果然是這個問題.這就坑爹了,這報錯報的那麼籠統,對於第一次遇到這種問題的我真的是夠了.

錯誤的原因是這樣的,在一個DEX檔案,你可以呼叫很多的方法,但你只能呼叫它們最前面的65,536個 ,因為這是在方法呼叫集合中的所有的空間了。Google提供一套官方的解決方案,在10月14日的時候釋出了MultiDex 支援庫,隨後幾周gradle在 v0.14.0版本中也支援了。如果你在使用 Android Studio,這個用起來很簡單。如果不是,強烈建議你遷移過來。因為Google很快就會不知處Eclipse外掛和舊的基於Ant的系統構建方式。

下面是解決這個問題的步驟:

第1步 
新增依賴於你的build.gradle支援MultiDex庫

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

第2步 
在buildType或productFlavor中開啟multiDexEnabled。

defaultConfig { 
   ... 
    multiDexEnabled true 
    ... 
}

現在,根據你的專案情況,你有3種選擇:

  1. 如果你沒有建立自己的Application 類,在你的清單檔案AndroidManifest.xml中配置android.support.multidex.MultiDexApplication就可以了。

       .... 
       android:name="android.support.multidex.MultiDexApplication" 
       ... 
    
  2. 如果你有自己的Application類了,讓它繼承 android.support.multidex.MultiDexApplication而不是android.app.Application,並在你的Application類新增下面方法
     @Override 
     protected void attachBaseContext(Context base) { 
        super.attachBaseContext(base); 
        MultiDex.install(this); 
     } 

  1. 如果你的Application繼承了其他的類,並且你不想改變或者沒辦法改變。按照下面的方法重寫attachBaseContext()

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

不論你選擇上面哪種,都會建立多個大小差不多的dex檔案代替單個龐大的dex檔案。執行的時候回同載入所有的這些dex檔案。

當你做了上面的配置之後再次進行編譯,那也不一定能編譯通過,可能會出現另外一個錯誤:

java.lang.OutOfMemoryError: GC overhead limit exceeded

Error:Execution failed for task ':app:transformClassesWithDexForDebug'.
> com.android.build.api.transform.TransformException: com.android.ide.common.process.ProcessException: org.gradle.process.internal.ExecException: Process 'command 'C:\Program Files\Java\jdk1.8.0_60\bin\java.exe'' finished with non-zero exit value 3

對於有很多依賴的專案,編譯可能因為下面的錯誤中斷

Error:Execution failed for task ':app:dexDebug'. 
... 
   Error Code: 
      3 
   Output: 
      UNEXPECTED TOP-LEVEL ERROR: 
      java.lang.OutOfMemoryError: GC overhead limit exceeded at com.android.dx.cf.cst.ConstantPoolParser.parse0(ConstantPoolParser.java:326) 
...

在build.gralde android標籤下面新增下面程式碼可以解決

dexOptions { 
   incremental true 
   javaMaxHeapSize "4g" 
}