zoukankan      html  css  js  c++  java
  • Android 分Dex (MultiDex)

    需要分Dex的理由想必大家都知道了.正是在ART以前的Android系统中,Dex文件对于方法索引是用一个short类型的数据来存放的.而short的最大值是65535,因此当项目足够大包含方法数目足够多超过了65535(包括引用的外部Lib里面的所有方法),当运行App,就会得到如下的错误提示.

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

     

    这个致命严重的Bug出现后,Android官方就写了一篇著名的Blog(这篇文章我读了五六遍,甚至连作者的Google+的照片我都看了两三次,我还是没有完全搞明白怎么Walkaround这个严重的问题).

    再后来,慢慢发展,有很多能人异士发挥自己的创造力,写了开源的Lib放在GitHub上分享给其他Android开发者们使用.HelloMultiDex, Secondary-Dex-Gradle等等.

    但是解铃还须系铃人,这种系统性的严重致命Bug,当然还是Android官方给出解决方案最让人放心.终于,我们还是等到了你,MultiDex Offical Solution.

    我推荐官方文档这篇GitHub的文章一起看会有更好的了解,少走弯路.

     

    下面说一说使用的步骤:

    1. 修改Gradle,导入'com.android.support:multidex:1.0.0',打开multiDexEnabled;

    android {
        compileSdkVersion 21
        buildToolsVersion "21.1.0"
    
        defaultConfig {
            ...
            minSdkVersion 14
            targetSdkVersion 21
            ...
    
            // Enabling multidex support.
            multiDexEnabled true
        }
        ...
    }
    
    dependencies {
      compile 'com.android.support:multidex:1.0.0'
    }

     

    2.修改Application.两种方法:

       1) 直接把Application替换成MultiDexApplication

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

      2) 在原来的Application中修改调用MultiDex.install(this);

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

     

    到这里其实MultiDex的配置已经完成了.

    但是,实际上下面介绍的3个问题也非常值得我们关注.

    1. 一些在二级Dex加载之前,可能会被调用到的类(比如静态变量的类),需要放在主Dex中.否则会ClassNotFoundError.

        通过修改Gradle,可以显式的把一些类放在Main Dex中.

    afterEvaluate {
        tasks.matching {
            it.name.startsWith('dex')
        }.each { dx ->
            if (dx.additionalParameters == null) {
                dx.additionalParameters = []
            }
            dx.additionalParameters += '--multi-dex'
            dx.additionalParameters += "--main-dex-list=$projectDir/<filename>".toString()
        }
    }

        上面是修改后的Gradle,其中<filename>是一个文本文件的文件名,存放在和这个Gradle脚本同一级的文件目录下.

        而这个文本文件的内容如下.实际就是把需要放在Main Dex的类罗列出来.

    android/support/multidex/BuildConfig/class
    android/support/multidex/MultiDex$V14/class
    android/support/multidex/MultiDex$V19/class
    android/support/multidex/MultiDex$V4/class
    android/support/multidex/MultiDex/class
    android/support/multidex/MultiDexApplication/class
    android/support/multidex/MultiDexExtractor$1/class
    android/support/multidex/MultiDexExtractor/class
    android/support/multidex/ZipUtil$CentralDirectory/class
    android/support/multidex/ZipUtil/class

    2. 如果用使用其他Lib,要保证这些Lib没有被preDex,否则可能会抛出下面的异常

    UNEXPECTED TOP-LEVEL EXCEPTION:
        com.android.dex.DexException: Library dex files are not supported in multi-dex mode
            at com.android.dx.command.dexer.Main.runMultiDex(Main.java:337)
            at com.android.dx.command.dexer.Main.run(Main.java:243)
            at com.android.dx.command.dexer.Main.main(Main.java:214)
            at com.android.dx.command.Main.main(Main.java:106)

       遇到这个异常,需要在Gradle中修改,让它不要对Lib做preDexing

    android {
    //  ...
        dexOptions {
            preDexLibraries = false
        }
    }

    3. 如果每次都打开MultiDex编译版本的话,会比平常用更多的时间(这个也容易理解,毕竟做了不少事情)

        Android的官方文档也给了我们一个小小的建议,利用Gradle建立两个Flavor.一个minSdkVersion设置成21,这是用了ART支持的Dex格式,避免了MultiDex的开销.而另外一个Flavor就是原本支持的最小sdkVersion.平时开发时候调试程序,就用前者的Flavor,发布版本打包就用后者的Flavor.

    android {
        productFlavors {
            // Define separate dev and prod product flavors.
            dev {
                // dev utilizes minSDKVersion = 21 to allow the Android gradle plugin
                // to pre-dex each module and produce an APK that can be tested on
                // Android Lollipop without time consuming dex merging processes.
                minSdkVersion 21
            }
            prod {
                // The actual minSdkVersion for the application.
                minSdkVersion 14
            }
        }
              ...
        buildTypes {
            release {
                runProguard true
                proguardFiles getDefaultProguardFile('proguard-android.txt'),
                                                     'proguard-rules.pro'
            }
        }
    }
    dependencies {
      compile 'com.android.support:multidex:1.0.0'
    }

    有了Android官方的支持后,MultiDex比最原始的解决方案简单多了.妈妈再也不用担心我们要分Dex啦!

  • 相关阅读:
    作业三(3)
    作业三(2)
    作业三(1)
    作业2(2)
    作业2(1)
    通读《构建之法》后有感
    自我介绍
    页面从服务器中浏览并添加图片显示
    lamda表达式 随机取数据的方法
    对js插件uploadify的一些操作
  • 原文地址:https://www.cnblogs.com/wingyip/p/4496028.html
Copyright © 2011-2022 走看看