Android中使用Dalvik虚拟机来运行应用程序,Dalvik虚拟机是有Google公司为Android平台量身定制的,它支持运行.dex格式的Java应用程序的运行。.dex文件将所有的.class文件打包,是专门Dalvik设计的一种压缩格式。Android项目在打包成APK时,项目中所有的.class文件都已被打包在.dex文件中了。在Android系统安装一个应用时,会对.dex文件进行优化,这个过程由专门的工具来处理,这个工具叫做DexOpt。DexOpt在第一次加载.dex文件时启动,这个过程会产生一个ODEX文件,即Optimized Dex。经过预处理后的ODEX文件,在运行时会比.dex文件在速度上快很多。但是,在早期的Android系统中,DexOpt有一个bug,它在执行时会把每一个类的方法id检索出来,存在一个链表结构中。这个链表的长度使用short类型保存的,这也就导致了方法的数目不能够超过65536个。这里的方法除了应用程序写的方法,还有第三方库中的方法,本地的方法。当一个项目的体积足够庞大时,这个方法数目的上限是不能满足需求的。在Andorid5.0之后,Android使用了ART(Android RunTime)来代替Dalvik虚拟机。ART本身就支持多dex的apk。它将多个dex文件组装成oat文件再运行。

ART与Dalvik的区别。

尽管Android在新版本中解决了这个问题,但是为了兼容低版本,我们还是要学习Android的dex分包。QQ空间的热修复技术也是基于dex分包实现的。


下面介绍一下如何在gradle中实现dex分包
首先在module的build.gradle文件的dependencies模块中添加如下语句,加载multidex包:

compile 'com.android.support:multidex:1.0.0'
然后在defaultConfig中添加注释处的语句,设置mutiDex模式:
defaultConfig {        applicationId "com.internetplus.yxy.intelligentspace"        minSdkVersion 15        targetSdkVersion 25        versionCode 1        versionName "1.0"        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"        multiDexEnabled true //设置multiDex模式    }

在AndroidManifest.xml文件中定义Application:

MyApplication类继承MultiDexApplication,并在onCreate中注册:

public class MyApplication extends MultiDexApplication {
public void onCreate() {        super.onCreate();        refWatcher = LeakCanary.install(this);        FileDownloader.init(this);        MultiDex.install(this);}}
   

或者在AndroidManifest.xml文件中直接使用 android.support.multidex.MultiDexApplication。还可以在MyApplication重写attachBaseContext()方法,并使用上文中的方法进行注册。

这样,最基本的分包就已经完成了,当你的apk方法数大于65536的时候,apk就会自动分包。包的名称为classes.dex(此为主dex包),classes2.dex,classes3.dex ...

如果你想做一些更详细的控制,还可以添加相应的参数,比如指定哪些类放在主dex包中,每个包的方法数上限。在gradle1.5之前,可以在afterEvaluate语句中添加additionalParameters来进行控制:

afterEvaluate {    tasks.matching {        it.name.startsWith('dex')    }.each { dx ->        if (dx.additionalParameters == null) {            dx.additionalParameters = []        }        dx.additionalParameters += '--multi-dex'        dx.additionalParameters += '--set-max-idx-number=20000' // 设置每个dex包的最多方法数为20000    }}
但在gradle1.5之后,修改了分包的参数api,这样的设置方法已经无法使用了。但在2.2版本中,这些api又开放了,不过要在DexOptions中进行添加设置:
dexOptions {        preDexLibraries = false        additionalParameters = ['--multi-dex',                                '--set-max-idx-number=20000']    }
使用之前记得把jdk升到1.8再使用。


另附一个查看dex包中方法数的方法:

建立两个文件:printhex.ps1 , dex-method-count.bat

printhex.ps1:

<#.SYNOPSISOutputs the number of methods in a dex file..PARAMETER PathSpecifies the path to a file. Wildcards are not permitted.#>param(  [parameter(Position=0,Mandatory=$TRUE)]    [String] $Path)if ( -not (test-path -literalpath $Path) ) {  write-error "Path '$Path' not found." -category ObjectNotFound  exit}$item = get-item -literalpath $Path -forceif ( -not ($? -and ($item -is [System.IO.FileInfo])) ) {  write-error "'$Path' is not a file in the file system." -category InvalidType  exit}if ( $item.Length -gt [UInt32]::MaxValue ) {  write-error "'$Path' is too large." -category OpenError  exit}$stream = [System.IO.File]::OpenRead($item.FullName)$buffer = new-object Byte[] 2$stream.Position = 88$bytesread = $stream.Read($buffer, 0, 2)$output = $buffer[0..1] #("{1:X2} {0:X2}") -f $output$outputdec = $buffer[1]*256 + $buffer[0]"Number of methods is " + $outputdec$stream.Close()

dex-method-count.bat:

@ECHO OFFIF "%1"=="" GOTO MissingFileNameErrorIF EXIST "%1" (GOTO ContinueProcessing) ELSE (GOTO FileDoesntExist):ContinueProcessingset FileNameToProcess=%1set FileNameForDx=%~n1.dexIF "%~x1"==".dex" GOTO ProcessWithPowerShellREM preprocess Jar with dxIF "%~x1"==".jar" (    ECHO Processing Jar %FileNameToProcess% with DX!    CALL dx --dex --output=%FileNameForDx% %FileNameToProcess%    set FileNameToProcess=%FileNameForDx%    IF ERRORLEVEL 1 GOTO DxProcessingError):ProcessWithPowerShellECHO Counting methods in DEX file %FileNameToProcess%CALL powershell -noexit -executionpolicy bypass "& ".\printhex.ps1" %FileNameToProcess%GOTO End:MissingFileNameError@ECHO Missing filename for processingGOTO End:DxProcessingError@ECHO Error processing file %1% with dx!GOTO End:FileDoesntExist@ECHO File %1% doesn't exist!GOTO End:End
然后将dex包和两个文件放到一个目录里面,打开命令行并切换到当前目录,运行:
dex-method-count.bat classes.dex
就可以看到dex包内的方法数了。

更多相关文章

  1. Android智能指针SP WP使用方法介绍
  2. Android命名规范(重点讲解:包名)
  3. Android高手进阶教程(十一)之----Android(安卓)通用获取Ip的方法
  4. Android面试系列文章2018之Android部分HandlerThread机制篇
  5. Android(安卓)Studio打包项目
  6. 浅谈Java中Collections.sort对List排序的两种方法
  7. NPM 和webpack 的基础使用
  8. Python list sort方法的具体使用
  9. 【阿里云镜像】使用阿里巴巴DNS镜像源——DNS配置教程

随机推荐

  1. 【android】LayoutInflater.inflate方法
  2. Android 四大组件,五大存储,六大布局
  3. Android Studio打包Signed APK 碰到的一
  4. Android图片压缩及内存缓存
  5. Android开发小技巧
  6. Android之ListActivity(一):布局与数据绑定
  7. 教你用电脑从 Google Play 下载 Android(
  8. 关于Android(安卓)Force Close 出现的原
  9. Android Binder 机制详解
  10. Android 开发中常用到的设计模式