安卓Dex超出方法数的坑

前言
之前在做项目的时候,我们经理向我反映,部分用户装不了应用,安装后进入应用就黑屏或者直接闪退。搞的我是一脸楞逼,经过各种折腾后总算找到了错误日志:

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)  

仔细翻查后发现这其实是安卓本身的一个“bug”,即限制了应用本身的方法数不得超过65535。安卓5.0之前的版本,每一个android应用中只会含有一个dex文件,在你项目中依赖了各种第三方sdk后会造成应用闪退(友盟,高德地图之类的)因为项目本身加上第三方库里的方法数已经超出了规定的65535上限。google针对该问题推出了multidex分包机制,在生成apk的时候,把整个应用拆成n个dex包(classes.dex、classes2.dex、classes3.dex),每个dex不超过64k个方法。但是5.0之前的系统对于这个问题就需要手动进行配置。

使用方法
一般在做项目的时候通常我们会写一个类继承Application,在该类中对一些值或者单列的类初始化,那么只要在这个类文件夹中件中重写attachBaseContext方法,让应用启动就加载第二、第三…个dex文件,就可规避掉这个问题。

public class MyApplication extends Application {
    public static MyApplication instance;

    public static MyApplication getInstance() {
        return instance;
    }

    public void onCreate() {
        super.onCreate();
        //单列返回值(能让程序在任意地方取到context)
        instance = this;
        init();
    }

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

或者直接继承MultiDexApplication这个类。

public class MyApplication extends MultiDexApplication{
  // ...........
}

OK,启动运行项目,结果又炸了。
这是因为默认的Dalvik 类加载器只会寻找classes.dex,所以需要将它们进行合并才能使得被识别。即在你项目引用的库文件的gradle中加入

 defaultConfig {
        minSdkVersion 14
        targetSdkVersion 27
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

        dexOptions{
            preDexLibraries = false
        }
    }

配置完成后即可在4.0的系统上运行项目了。

发布了4 篇原创文章 · 获赞 4 · 访问量 1407

猜你喜欢

转载自blog.csdn.net/heromrwang/article/details/82623974