多Dex加载方案对比

随着业务扩张,代码量越来越大,apk中单个dex方法数超过65K,就需要dex分包,Google官方推出了MultiDex来解决65K的问题,区分不同的Android虚拟机,会有一些问题。

Dalvik上,使用JIT(just in time),应用运行时,需要先将dex转换成os上可以运行的机器码,在此过程中,还会对dex文件进行优化(dexopt),因此在应用第一次启动时,会经历这些过程,apk解压->dexopt->加载dex->字节码转换->启动,在加载dex过程中,安装第二个dex之后的dex涉及到io操作,在dex加载完成之前,应用需要一直等待,此过程耗时较长,如果dex文件过大,还会造成ANR;

ART上,使用oat(Ahead of time),在应用安装时,dex就会被解压优化完成,转换成可执行的机器码,之后应用在启动时,只需要加载机器码即可,所以不会出现启动ANR的问题。

为了解决Dalvik上冷启动慢的问题,通常的方法是自定义第二个dex的加载流程,常用方案有以下几种:

方案

原理

接入技术难度

优点

不足

风险

方案

原理

接入技术难度

优点

不足

风险

Google MultiDex

第一个启动的进程的主线程上解压安装,同步执行,dex全部安装完成之后,启动应用

最简单

dex加载完成之后,应用才真正开始运行,不会出现NoClassDefFoundError

启动慢

dex文件过大时,在低配设备上可能会出现ANR、黑屏

微信/QQ

1、将dex文件放在assets文件夹下,加载前校验md5(官方没校验);

2、四大组件的直接间接依赖都直接放在主dex中;

3、判断是否已经dexopt,若已经dexopt,即放在attachBaseContext加载,反之放于地球中用线程加载(若判断revision改变,即将dex以及dexopt目录清空。只需简单判断两个目录dex名称、数量是否与配置文件的一致)

最复杂,需要自己写脚本扫描依赖集,以及自定义dex加载过程

启动不会发生ANR,比Google的MultiDex更快

太过复杂,每次都需重新扫描依赖集,而且使用的是比较大的间接依赖集

Facebook

1、使用自己开源的buck进行dex分包;

2、将加载Dex的逻辑放于单独的nodex进程,这是一个非常简单、轻量级的进程。它没有任何的ContentProvider,只有有限的几个Activity、Service;

3、将启动LauncherActivity放在nodex进程,启动时在nodex进程中安装dex,主进程一直等待,dex安装完成之后,启动应用;

比Google的MultiDex稍复杂一些

依赖集非常简单,同时首次加载Dex时也不会卡死

启动主进程之前,必须先启动nodex进程,额外增加了启动时间(大约几百毫秒)

美团

1、使用gradle插件进行分包,编译期生成dex文件时,将入口Activity直接依赖的类放入主dex中;

2、多dex安装时,先加载主dex,启动应用,后续dex异步安装,安装完成之后,提供回调方法;

3、hook Activity的启动过程,如果在异步加载dex期间就引用了未加载的类进行Activity跳转,启动一个Loading的页面,直到所有dex加载完成;

接入很简单,但是需要彻底解耦,否则主dex的方法数很容易超过65K,编译不通过

启动时间最快

有内部RD支持,方便定位问题

需要代码高度解耦,要改动业务代码

容易出现NoClassDefFoundError

你可能感兴趣的:(Android)