Gradle使用详解(六) 之 如何解决65535方法限制

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lyz_zyx/article/details/83539766

当我们工程版本迭代和业务需求越来越多时,代码量自然也就越来越多。所以在日常开发中会难免会碰到方法个数超过限制65535的错误。原因就是:Java源文件在打包成一个DEX文件,这个文件就是优化过的、Dalvik虚拟机可执行的文件,Dalvik虚拟机在执行DEX文件时,它使用了short这个类型索引DEX文件中的方法,这意味着单个DEX文件可以被定义的方法最多只能是65535个,当超过这个数量时就会发生编译错误。

我们在前面文章《Gradle使用详解(三) 之 Android Gradle插件配置详解》也简单提过,你可以通过dexOptions{}闭包里的jumboMode字段设置为true,从而忽略65535方法数限制的检查,但是只是忽略,如若你的apk明确不会运行在5.0以下的手机上的话,倒是没有问题,否则问题还是得解决。

解决方法超过65535最直接的方法就是删除代码,例如如果引用了大量的第三方aar或jar库的话,其实内部会有大量多余的代码,可以考虑修改它们,来删除无用的功能代码。还有就是我们在版本开发迭代过程中产生一些已经过时无用的功能,然后把这类代码删除。但是,如果上述方法你都已经尝试过后还是存在65535方法超过限制的话,那就只能使用生成多个DEX文件,使每个DEX文件的方法数量都不超过65535,这样就能彻底的解决。

对于Android 5.0及以上的手机,使用了ART的运行时方式,可以支持APP有多个DEX文件。ART在安装APP时执行预编译,把多个DEX文件合并成一个oat文件执行。但对于Android5.0以下手机的话,Dalvik虚拟机限制每个APP只能有一个class.dex,要使用它们,就得使用Android为提供的Mulidex库。例如:

android {
    ……
    defaultConfig {
        ……
        multiDexEnabled true
    }
    ……
}
dependencies {
    ……
    implementation 'com.android.support:multidex:1.0.0'
}

我们要想使用Multidex,那就得在defaultConfig{}、buildType{} 或 productFlavor{} 中给multiDexEnabled字段设置为true,这样就能开启Mulidex,使方法达到65535后生成多个DEX文件。但是前面提到Android 5.0以下手机只能有一个class.dex,所以我们要让虚拟机把生成的几个dex文件加载到一个class.dex中去。接着还要配置Mulidex库的依赖。因为我们我们要在Application中去处理它。

情况一、Mulidex提供了现成的Application其名字是MultiDexApplication,如果我们工程中没有自定义Application的话,那直接在AndroidManifest.xml中配置它即可,如:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.zyx.myapplication">

    <application
        android:name="android.support.multidex.MultiDexApplication"
        ……>
        ……
    </application>
     ……
</manifest>

情况二、如果本来就存在自定义的Application,那么使自定义的Application继承MultiDexApplication也是可以的,如:

package com.zyx.myapplication;

import android.support.multidex.MultiDexApplication;

public class MyApplication extends MultiDexApplication {
    ……
}

情况三、又如果本来就存在自定义的Application,而又已经有继承的其他功能的Application的话,可以通过重写attachBaseContext方法也是可以的:

package com.zyx.myapplication;

import android.app.Application;
import android.content.Context;
import android.support.multidex.MultiDex;

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

attachBaseContext是Application创建后最先回调的方法,我们在此方法内调用一句代码:MultiDex.install(this);即可,因为从源码可以了解到这是和继承MultiDexApplication是一样的。我们在开发过程中建议使用最后情况三的方式来处理,因为这样可以方便的进行Android SDK 版本的判定,若果是Android 5.0以下情况才调用MultiDex.install(this);这行代码,就如:

package com.zyx.myapplication;

import android.app.Application;
import android.content.Context;
import android.os.Build;
import android.support.multidex.MultiDex;

public class MyApplication extends Application {
    @Override
    protected void attachBaseContext(Context context) {
        super.attachBaseContext(context);
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
            MultiDex.install(this);
        }
    }
}

总结

  1. Dalvik虚拟机在执行DEX文件时,它使用了short这个类型索引DEX文件中的方法,所以DEX文件可以被定义的方法最多只能是65535个
  2. Android程序打包时,Android Gradle会自动判断工程中方法是否有超过65535个,如果没有超过会正常地生成一个classes.dex文件;如果超过了就会报出65535的编译错误
  3. 我们可以通过Mulidex来解决65535方法超过的问题,它会在超过方法数时就会生成1classes.dex文件和若干个附属的DEX文件,如classes2.dex…
  4. DEX安装在机器上的过程比较复杂,体积较大时可能会在性能够差的机器上造成ANR,虽然Mulidex可以解决65535的问题,但是我们在平时写代码时还是要注意尽量避免滥用第三方库和避免冗余代码。

 

 

——本文部分内容参考自《Android Gradle权威指南》

猜你喜欢

转载自blog.csdn.net/lyz_zyx/article/details/83539766