Dalvik下mutidex加载(只是总结备用,并没有分析源码)

来源:互联网 发布:php代码 编辑:程序博客网 时间:2024/05/22 05:12

mutidex之前度过源码,其实并不难。这里做个总结,自己以后备用(比如mutidex异步加载,插件化等,dex动态加载还是挺重要的)。大家如果想分析下源码,也可以看下MultiDex工作原理分析和优化方案这个博客,分析的很到位。我这里就不赘述了。

Dalvik

当初设计Dalvik的时候,设定的是 安装app的时候只会把主dex放到classLoader中类型是DexPathList的成员变量pathList。DexPathList持有DexFile数组dexElements(dexElements其实是Element[],Element是把DexFile又封装了一下,不过理解成DexFile也没什么问题。DexFile可以理解就是dex文件的封装,DexFile持有dex的路径,和一些方法比如loadClass()在真正加载到内存时调用;openDexFile()在new DexFile()时调用,用于检查dex文件是不是正确,以及进行dex->odex的优化工作)。在app启动后,application#attachBaseContext()时,mutidex会检查是不是之前已经有了缓存的从dex 文件,如果没有,那么就从apk中解压出来那些从dex(耗时)文件。如果有,那么就使用这些缓存的从dex文件。注意缓存的是dex文件,不是DexFile。所以每次冷启动app时,不管用的是缓存的dex文件还是新解压的dex文件,都需要dex文件->new DexFile的过程,前面说了在new DexFile时,会调用DexFile#openDexFile(),这个方法会进行dex->odex的优化工作(这里的odex只是对dex进行了优化,并不是生成机器码),dex->odex是显著耗时的,所以即使用了dex文件缓存,使用mutidex还是会有显著耗时。有了dex文件后,就会调用MultiDex#installSecondaryDexes方法,在installSecondaryDexes()方法内,会进行dex文件->new DexFile->new Element(dexFile)->反射拿到classLoader中类型为DexPathList的成员变量pathList,把前面的element放到DexPathList的dexElements数组中。在new DexFile时,会调用DexFile#openDexFile(),这个方法会进行dex->odex的优化工作,dex->odex是显著耗时的。

在app运行时,如果需要某个类,那个类如果还没有加到内存中,那么会去classLoader的DexPathList中的DexFile数组中去找,是不是有哪个dexFile含有对应的类,如果有,那么就调用对应的dexFile#loadClass()将对应的类文件加载到内存。如果没有找到,那么抛ClassNotFound异常。

ART

android5.0及以上(api对应21)的机子是采用的art系统。在这个系统上安装apk的时候(art系统吸取了之前的经验),会把apk中所有的dex翻译成机器码,预编译成多个oat文件(推测:之后会把这些oat文件放到classloader的dexpathlist中)。所以有了art系统,app启动的时候,就不需要在application初始化阶段执Multidex.install(this);。Dalvik系统运行时,如果需要加载某各类,需要从classloader中的dexlist中寻找对应的字节码文件路径来加载到内存,并翻译成机器码。而ART系统运行时,不需要再把字节码文件翻译成机器码的过程了,因为在安装时已经把所有dex都翻译成oat文件了。

但是,虽然在application初始化阶段不需要执行Multidex.install(this)。但是如果项目的总方法数超过了64k,还是需要在构建阶段把项目达成多个dex(一个dex文件不能超过64k方法数)。所以在构建apk时还是需要mutidex进行分包,5.0及以上机器运行时不再需要mutidex的安装方案。

在构建apk时,不管minsdk版本是多少,虽然都需要使用mutidex分包。但是系统还是做了一些优化。如果设置的minsdk<21,那么在分包时会做很多决策,这些决策决定哪些类放到主dex,哪些类放到从dex中。这是一个很耗时的决策,因为构建时间会很长。如果设置的minsdk>=21,那么意味着你的apk安装在android5.0及以上,也就是art系统上(所有的dex在apk安装时都会翻译成机器码,不需要mutidex.install()),也就无所谓哪个类在主dex,那个类在从dex了。所以android gradle 插件(比如3.0.0版本额)在构建工程时,发现minsdk>=21。就会把每一个模块\每一个依赖项都弄成一个dex,不再决策哪些类放到主dex了,哪些放到从dex了。这样能减少构建时间。这也为我们减少项目构建时间提供了一个思路:可以设置一个minSdkVersion 21的flavor,专门用于开发阶段的apk构建。

    android {defaultConfig {    ...    multiDexEnabled true}productFlavors {    dev {        // Enable pre-dexing to produce an APK that can be tested on        // Android 5.0+ without the time-consuming DEX build processes.        minSdkVersion 21    }    prod {        // The actual minSdkVersion for the production version.        minSdkVersion 14    }}buildTypes {    release {        minifyEnabled true        proguardFiles getDefaultProguardFile('proguard-android.txt'),                                             'proguard-rules.pro'    }}}dependencies {    compile 'com.android.support:multidex:1.0.1' }   

参考文章:

配置方法数超过 64K 的应用

MultiDex工作原理分析和优化方案

Dalvik,ART与ODEX相爱相生

阅读全文
0 0
原创粉丝点击