Multidex何弃疗
来源:互联网 发布:rk3399平板 ubuntu 编辑:程序博客网 时间:2024/04/28 20:32
当我们的app越来越大时,project build时可能会失败,报下面的错误。
Conversion to Dalvik format failed:Unable to execute dex: method ID not in [0, 0xffff]: 65536
或者是这样:
trouble writing output:Too many field references: 131000; max is 65536.You may try using --multi-dex option.
上面的错误都是说dex文件中索引id超过了64k范围,只是使用不同版本android编译系统提示不一样而已。通常的理解是dex文件引用的方法数索引使用short类型保存,决定了单个dex包最大的方法数只有64k。具体分析,可以参考由Android 65K方法数限制引发的思考。
Google官方解决方案——Multidex
google为了解决这个问题提出了Multidex,如果工程方法数超过了64k,可以自动将我们的代码和资源拆分成多个dex文件。Android 5.0之前可以使用multidex support library来实现,配置也比较简单。
- build tools版本升到21.1以上,gradle添加multidex依赖,并且启用multidex选项
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'}
- 使用MultidexApplication
三种方法,按项目需求选择一种即可:
1)可以在manifest中直接指定project Application为MultidexApplication;
2)可以让项目的Application继承MultidexApplication
3)不继承MultidexApplication也可以,直接在Application的attachBaseContext()方法中调用MultiDex.install(this);方法加载multidex
protected void attachBaseContext(Context base) { super.attachBaseContext(base); MultiDex.install(this);}
Android 5.0之后使用ART(Android Runtime),ART原生支持从apk中加载multidex。应用安装时,ART会扫描apk中所有的dex文件,然后编译成单个oat文件供Android设备运行。目前市场上android 4.4的占有率还是比较高的,因此multidex方案还是有必要的。
另外,应用在启动时,系统会负责帮助我们加载主dex文件,而只有在Application实例化的时候才会调用MultiDex.install(this)方法加载二级以及之后的dex。由于android系统在退出应用时只要不杀app进程,进程会存活一段时间以便下次复用,这样能够加快应用启动速度。因此,只有在应用冷启的时候才会去加载二级以及之后的dex文件。
Multidex方案缺点(Android 4.0以下系统)
(1)Multidex方案是同步加载的,如果二级dex文件较大的话,应用启动时可能会出现ANR。因此,虽然我们可以不用担心方法数超过上限的问题,但是App瘦身工作还是要做的。可以开启ProGuard混淆,帮助我们删除不需要的依赖以及无用的资源和代码,可以帮助我们减小App size。
(2)Android 4.0 之前系统,存在Dalvik linearAlloc bug,Mutidex可能会失效,也就可能发生crash。
(3)开启了Multidex的应用需要分配很大的内存,Android 5.0以下的系统可能会触发Dalvik linearAlloc 的内存限制,从而造成crash。
Multidex安装过程简析
(1)首先判断当前系统VM是否已经支持multidex;如果支持,弃用使用multidex support library手动加载mutidex的方案。
(2)判断当前SDK_INT是否支持multidex,SDK_INT小于4不支持。
(3)判断secondary dex是否已经安装,防止多进程创建时重复执行安装。
(4)删除之前安装时提取的dex文件,dex文件存放目录为:context.getFilesDir()+”/secondary-dexes”
(5)查看是否有dex文件缓存,如果有直接从缓存中取得dex文件列表;如果没有,解析apk提取dex文件列表
/*** 获取dex文件列表**/static List<File> load(Context context, ApplicationInfo applicationInfo, File dexDir, boolean forceReload) throws IOException { Log.i("MultiDex", "MultiDexExtractor.load(" + applicationInfo.sourceDir + ", " + forceReload + ")"); File sourceApk = new File(applicationInfo.sourceDir); long currentCrc = getZipCrc(sourceApk); List files; if(!forceReload && !isModified(context, sourceApk, currentCrc)) { try { files = loadExistingExtractions(context, sourceApk, dexDir); } catch (IOException var9) { Log.w("MultiDex", "Failed to reload existing extracted secondary dex files, falling back to fresh extraction", var9); files = performExtractions(sourceApk, dexDir); putStoredApkInfo(context, getTimeStamp(sourceApk), currentCrc, files.size() + 1); } } else { Log.i("MultiDex", "Detected that extraction must be performed."); files = performExtractions(sourceApk, dexDir); putStoredApkInfo(context, getTimeStamp(sourceApk), currentCrc, files.size() + 1); } Log.i("MultiDex", "load found " + files.size() + " secondary dex files"); return files;}
dex文件名从classes2.dex开始,每个dex文件解析如果出错有三次重试机会。dex文件解析完成后putStoredApkInfo()方法在SharedPreferences中保存dex的timestamp、crc校验和数量信息。
(6)安装dex文件列表。不同的android版本有不同的实现方式,如下是api19及以上实现。
private static void install(ClassLoader loader, List<File> additionalClassPathEntries, File optimizedDirectory) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException { Field pathListField = MultiDex.findField(loader, "pathList"); Object dexPathList = pathListField.get(loader); ArrayList suppressedExceptions = new ArrayList(); MultiDex.expandFieldArray(dexPathList, "dexElements", makeDexElements(dexPathList, new ArrayList(additionalClassPathEntries), optimizedDirectory, suppressedExceptions)); ... }}// 将secondary dex 路径加入到primary dex路径之后private static void expandFieldArray(Object instance, String fieldName, Object[] extraElements) throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException { Field jlrField = findField(instance, fieldName); Object[] original = (Object[])((Object[])jlrField.get(instance)); Object[] combined = (Object[])((Object[])Array.newInstance(original.getClass().getComponentType(), original.length + extraElements.length)); System.arraycopy(original, 0, combined, 0, original.length); System.arraycopy(extraElements, 0, combined, original.length, extraElements.length); jlrField.set(instance, combined);}private static Object[] makeDexElements(Object dexPathList, ArrayList<File> files, File optimizedDirectory, ArrayList<IOException> suppressedExceptions) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException { Method makeDexElements = MultiDex.findMethod(dexPathList, "makeDexElements", new Class[]{ArrayList.class, File.class, ArrayList.class}); return (Object[])((Object[])makeDexElements.invoke(dexPathList, new Object[]{files, optimizedDirectory, suppressedExceptions}));}
从源码中可以看出,dex的安装过程首先利用反射调用DexPathList的makeDexElements方法将secondary dex文件包装成Element对象,之后再利用反射将Element对象插入DexPathList的dexElements对象中,从而达到修改ClassLoader的dexPathList效果,这样ClassLoader就能找到secondary dex中的代码资源了。
美团Dex自动拆包及动态加载
美团的这套机制是在multidex基础上提出的,主要针对multidex在Android 4.0以下系统存在的缺点进行优化和改进,解决应用冷启速度慢甚至是crash的问题以及linearAlloc缺陷和限制的问题。冷启crash是因为MultiDex.install(this)操作比较耗时导致的,因此可以考虑放到异步线程中去加载。同时由于异步带来时间上的不确定性,必须保证主dex文件包含了应用启动以及首页等所需的全部资源,并且确保在使用二级dex文件中资源时,二级dex已经加载完毕。针对linearAlloc缺陷和限制的问题,可以考虑人工干涉控制各个dex大小来规避。
综上,美团这套机制主要需要解决两个问题:
(1)人工干预dex拆分,包括dex内容、dex大小、dex个数
(2)保证使用各个dex之前,dex已经加载完成
参考文档:
官方multidex文档
https://developer.android.com/studio/build/multidex.html#mdex-gradle
美团Android DEX自动拆包及动态加载简介
http://tech.meituan.com/mt-android-auto-split-dex.html
- Multidex何弃疗
- 网游自主研发响彻云霄,何弃拿来主义?
- 放弃,弃疗!
- MultiDex
- MultiDex
- MultiDex
- multidex
- multidex
- 弃。
- (弃疗搁置)poj 1821 Fence
- 堵呜一姿仿仙栋涝夹何疗
- MultiDex源码
- MultiDex使用方法
- android MultiDex
- 遭遇MultiDex
- MultiDex分包
- 关于MultiDex
- 遭遇MultiDex
- linux source命令
- 问题 R: 赫夫曼编码
- Cubietruck---14. binder分析_深入理解android第六章笔记
- “个人总结”最基础博弈套路,实力山寨
- 东方输入法真的有流氓么?
- Multidex何弃疗
- Cubietruck---15. input系统分析2
- iOS开发 UITabBar角标 红点形式 (tabBarItem.badgeValue)
- Cubietruck---16.设备的添加及数据分析
- hdu_5221_Occupation(树剖)
- 手把手教你禁止流氓软件进入电脑!小白福因~~~~
- Cubietruck---17.键盘设备的添加及数据流程分析
- Docker中使用OverlayFS
- 现在软件是不是越来越流氓了,越来越任性了.