Android Retrofit報錯NoClassDefFoundError異常

使用Retrofit 2時踩了個坑,自己封裝的Retrofit工具在4.4的手機上跑崩了,測試了下機型,發現在Android 5.x以上的手機就不會出現這樣的情況,而在Android 4.x手機上這個問題是必現的

錯誤信息

java.lang.NoClassDefFoundError: retrofit2.Retrofit$Builder

一看到這個錯誤信息,馬上聯想到是否是類缺失了,但是這裏指向的是Retrofit2.Retrofit$Builder,導入第三方類庫怎麼還會缺少類呢,而且如果是類缺失,那麼在程序編譯期間就會報錯的,仔細一看是自己眼花了,NoClassDefFoundError錯誤和ClassNotFoundException經常容易被搞混,這兩個錯誤類型雖然都指的是找不到類,但是差異還是挺大的

ClassNotFoundExceptio

這個錯誤比較好解決,就是程序找不到指定的class類,就會出現這個問題,通常發生在程序的編譯期間

NoClassDefFoundError

這個錯誤就比較難找了,在程序正常編譯後還報這個未找到類的異常,也就是說這個class類在程序的編譯階段並沒有缺失,但是在程序運行階段,無法把它正常的從內存中加載出來,我們通常使用new方法來實例化一個類,如果這個類在程序運行的時候“失蹤”了,那麼就會拋出這個異常。

    class A {
        public String getMethod(){
            return "method";
        }
    }
    public class B {
        public static void main(String[] args)
        {
            A a = new A();
            System.out.println(a.getMethod());
        }
    }

就比如說,我們有兩個類A和B,B調用A中的方法,我們編譯好後,實際上是生成了兩個.class文件,這個時候如果我們把A.class文件刪掉,再運行程序,那麼就會出現NoClassDefFoundError異常了。

解決方法

瞭解了異常產生的原因,就開始對症下藥了,居然在編譯期間沒有出錯,那麼說明類文件並沒有缺失,而是在編譯完成後,運行程序時無法正常的獲取到Retrofit$Builder類。

在Android中,我們經常會使用到分包方法,即multiDexEnabled,尤其是當我們的程序應用了大量第三方框架的時候,這個參數就更重要了,因爲Android中編譯的單個.dex文件最多支持65536個方法,而如果大於這個方法數,就需要使用到multiDexEnabled方法對Dalvik可執行文件.dex進行分包了,而在分包的時候就可能把Retrofit需要使用到的方法分到不同的dex文件中,所以問題應該就出在multiDexEnabled的使用上了。

android {
    ...
    defaultConfig {
        ...
        multiDexEnabled true
    }
    ...
}

這個分包方法,是在Android 5.0之後提供的,如果程序運行在5.0以上的手機,版本設置爲minSdkVersion 21以上的應用來說,以上這麼配置的方式就可以了

而我在程序中指定的最低支持到的版本是API 19,所以爲了兼容Android 5.0以下的手機,需要在build.gradle添加個依賴庫com.android.support:multidex:1.0.1

android {
    ...
    defaultConfig {
        ...
        multiDexEnabled true
    }
    ...
}

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

同時,對於被我們替換的Application類,需要繼承的是MultiDexApplication,而不是Application

public class AppApplication extends MultiDexApplication {...}

通過以上的正確方法配置好了之後,再次運行,就沒有再報NoClassDefFoundError錯誤了。

  • 如果你不想繼承MultiDexApplication類,而需要繼承其它類型的Application類,那麼可以通過重寫其attachBaseContext方法,在其中
    手動調用 Dalvik 可執行文件分包方法MultiDex.install()
    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(context);
        MultiDex.install(this);
    }
  • 如果沒有替換Application類,那麼就需要在配置文件AndroidManifest.xml中指定<application>標籤的name爲android.support.multidex.MultiDexApplication
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.text">
    <application
            android:name="android.support.multidex.MultiDexApplication" >
            ...
    </application>
</manifest>

總結

事實上這個錯誤並不是由於Retrofit本身造成的,而是錯誤的使用multiDexEnabled方法造成的,對於多Android版本的兼容性處理的不夠好,導致出現了上述問題

當應用程序指定了最小支持的版本號時,應該以這個最小版本號爲準,最好適配工作,使用兼容包去處理高低版本之間的差異性問題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章