android MultiDex 原理(一)


Android分包MultiDex原理详解

转载请注明:http://blog.csdn.net/djy1992/article/details/51162013 下一篇文章:android MultiDex 原理下遇见的N个深坑(二)

MultiDex的产生背景

         当Android系统安装一个应用的时候,有一步是对Dex进行优化,这个过程有一个专门的工具来处理,叫DexOpt。DexOpt的执行过程是在第一次加载Dex文件的时候执行的。这个过程会生成一个ODEX文件,即Optimised Dex。执行ODex的效率会比直接执行Dex文件的效率要高很多。

但是在早期的Android系统中,DexOpt有一个问题,DexOpt会把每一个类的方法id检索起来,存在一个链表结构里面。但是这个链表的长度是用一个short类型来保存的,导致了方法id的数目不能够超过65536个。当一个项目足够大的时候,显然这个方法数的上限是不够的。尽管在新版本的Android系统中,DexOpt修复了这个问题,但是我们仍然需要对低版本的Android系统做兼容。

为了解决方法数超限的问题,需要将该dex文件拆成两个或多个,为此谷歌官方推出了multidex兼容包,配合AndroidStudio实现了一个APK包含多个dex的功能。


MultiDex的简要原理

我们以APK中有两个dex文件为例,第二个dex文件为classes2.dex。

  1. 兼容包在Applicaion实例化之后,会检查系统版本是否支持 multidex,classes2.dex是否需要安装。
  2. 如果需要安装则会从APK中解压出classes2.dex并将其拷贝到应用的沙盒目录下。
  3. 通过反射将classes2.dex注入到当前的classloader中。

下面引入一下官方的文档。

https://developer.android.com/tools/building/multidex.html#about 
笔者,针对官方文档的翻译如下:


构建超过65K方法的App

随着Android设备的慢慢发展,App的大小会变得越来越大。当我们在开发App的时候由于报的大小和引用库的原因,我们在编译我们项目的时候通常会遇到下面一个错误:

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

当然,也有一些系统设备会出现以下log信息,不过反馈的是同一个问题:

trouble writing output:Too many field references: 131000; max is 65536.You may try using --multi-dex option.

这两个错误条件显示一个共同的数字:65536。这个数字,它表示的是你在一个dex包中的函数方法超过了65535个。

如果你已经构建了一个Android App时,并收到了这个错误,那么恭喜你,你有很多代码!

下面我们就具体说说,如何解决这个问题。


A.关于65K方法限制

我们知道Android中的可执行伟剑都存储在dex文件中,其中包含已编译的代码来运行你的应用程序。Dalvik虚拟机对可执行dex文件的规格是有方法限制的,即一个单一的dex文件的方法总数最多为65536。

其中包括:

  • 引用的Android Framework方法
  • library的方法
  • 我们自己书写代码的方法。

  • B.限制

为了突破这个方法数的限制,我们就提出了一个方案——生成多个dex文件。这个多个dex文件的方案,我们又称为multidex方案配置。

Multidex支持Android 5.0之前的版本 
   Android5.0版本的平台之前,Android使用的是Dalvik Runtime执行的程序代码。默认情况下,限制应用到一个单一的classes.dex。

Dalvik字节码文件每APK。为了绕过这个限制,你可以使用multidex支持库,成为你的应用程序的主要部分和DEX文件进行管理,获得额外的dex文件,它们包含的代码。

Multidex支持Android 5.0及更高版本 
    Android 5.0和更高的Runtime 如art,本身就支持从应用的APK文件加载多个DEX文件。art支持预编译的应用程序在安装时扫描类(..)。Dex文件编译成一个单一的Android设备上执行.oat文件。


一、避免65K限制

当你确定使用multidex的分包策略的时候,请你先确定自己的代码中都是优秀的。你还需要做以下几步:

  • 去掉一些未使用的import和library
  • 使用ProGuard去掉一些未使用的代码

二、用Gradle配置使用Multidex

 怎么使用用Gradle配置使用MultidexAndroid 的 Gradle插件在 Android Build Tool 21.1开始就支持使用multidex了。

设置你的应用程序开发项目中使用multidex配置,要求你做出一些修改您的应用程序开发项目:

  • 修改Gradle的配置,支持multidex
  • 修改你的manifest。让其支持multidexapplication类

修改Gradle的build如下:

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}

Tips: 你可以在Gradle配置文件中的 multiDexEnabled 在 defaultConfig、 
buildType、productFlavor选项设置。

在manifest文件中,添加MultidexApplication Class的引用,如下所示:

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

当然,如果你重写了 Application,就对自定义Application的继承方式做一个修改。


Multidex的方式的局限性

虽然我们开起来multidex是一个极好的东西,但是multidex还是存在自己的局限性,我们在开发测试之前要清楚局限性是什么:

  1. 如果二DEX文件太大,安装分割dex文件是一个复杂的过程,可能会导致应用程序无响应(ANR)的错误。在这种情况下,你应该尽量的减小dex文件的大小和删除无用的逻辑,而不是完全依赖于multidex。
  2. 在Android 4.0设备(API Level 14)之前,由于Dalvik linearalloc bug(问题22586),multidex很可能是无法运行的。如果希望运行在Level 14之前的Android系统版本,请先确保完整的测试和使用。
  3. 应用程序使用了multiedex配置的,会造成使用比较大的内存。当然,可能还会引起dalvik虚拟机的崩溃(issue 78035)。
  4. 对于应用程序比较复杂的,存在较多的library的项目。multidex可能会造成不同依赖项目间的dex文件函数相互调用,找不到方法。

优化multidex开发和构建

一个multidex的配置,对系统apk的构建、签名、打包复杂性大大的增加。这就意味着,你每一次的构建过程都是相当耗时的。

为了加快我们的开发速度,加快构建的过程,我们可以在Gradle productFlavors新建出来一个 development flavor 和 production flavor 来满足我们不同构建需求。

下面是一个列子演示我们如何设置这些flavors在Gradle build文件中:

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}

在你完成了伤处的配置修改之后,你配置productFlavor 和 buildType来使用 ,devDebug 变种app。使用这些变种app,可以设置proguard disable、multidex enable方便我们测试。

这些配置需要针对Android Gradle插件做如下操作:

  1. 在分包前,编译应用程序中的每一个module包括依赖项目,这个步骤称为 pre-dexing。
  2. include每一个dex文件
  3. 最重要的是,对于主dex文件,不会做切分。以保证计算速度。

这样设置既能够保证我们的最终报是一个使用了multidex模式的,而又不影响我们平时开发的测试效率。


在Android Studio中使用变种App

使用multidex工具构建变种App是非常方便的。在Android Studio允许我们选择这种变种构建方式的接口。

使用Android Studio构建 “devDebug”构建变种app需要完成两步:

  • 打开变种编辑窗口,选择favorites选项。
  • 点击编译不同的变种,如下图所示 
转载请注明:http://blog.csdn.net/djy1992/article/details/51162013 下一篇文章:android MultiDex 原理下遇见的N个深坑(二)

更多相关文章

  1. 浅谈Java中Collections.sort对List排序的两种方法
  2. 箭头函数的基础使用
  3. NPM 和webpack 的基础使用
  4. Python list sort方法的具体使用
  5. 【阿里云镜像】使用阿里巴巴DNS镜像源——DNS配置教程
  6. python list.sort()根据多个关键字排序的方法实现
  7. Android(安卓)Project Structure
  8. 【Android开发基础】应用界面主题Theme使用方法
  9. Android(安卓)打开本地文件兼容7.0

随机推荐

  1. PMP备考心得
  2. Android学习笔记3:使用日志工具
  3. 堆排序就这么简单
  4. 阻塞队列 BlockingQueue
  5. redis集群教程(二)
  6. 由浅入深,走进Python装饰器-----第五篇:
  7. SharePoint 解决方案:如何获取Library或者
  8. 希尔排序就这么简单
  9. Druid数据库连接池就是这么简单
  10. Ruby和Python哪个更强大?学习分析