- 浏览: 5826007 次
- 性别:
- 来自: 上海
文章分类
- 全部博客 (890)
- WindowsPhone (0)
- android (88)
- android快速迭代 (17)
- android基础 (34)
- android进阶 (172)
- android高级 (0)
- android拾遗 (85)
- android动画&效果 (68)
- Material Design (13)
- LUA (5)
- j2me (32)
- jQuery (39)
- spring (26)
- hibernate (20)
- struts (26)
- tomcat (9)
- javascript+css+html (62)
- jsp+servlet+javabean (14)
- java (37)
- velocity+FCKeditor (13)
- linux+批处理 (9)
- mysql (19)
- MyEclipse (9)
- ajax (7)
- wap (8)
- j2ee+apache (24)
- 其他 (13)
- phonegap (35)
最新评论
-
Memories_NC:
本地lua脚本终于执行成功了,虽然不是通过redis
java中调用lua脚本语言1 -
ZHOU452840622:
大神://处理返回的接收状态 这个好像没有监听到 遇 ...
android 发送短信的两种方式 -
PXY:
拦截部分地址,怎么写的for(int i=0;i<lis ...
判断是否登录的拦截器SessionFilter -
maotou1988:
Android控件之带清空按钮(功能)的AutoComplet ...
自定义AutoCompleteTextView -
yangmaolinpl:
希望有表例子更好。。。,不过也看明白了。
浅谈onInterceptTouchEvent、onTouchEvent与onTouch
随着应用不断迭代更新,业务线的扩展,应用越来越大(比如:集成了各种第三方SDK或者公共开源的Library文件、jar文件)这样一来,项目耦合性就很高,重复作用的类就越来越多了,SO:问题就来了。
相信大家在做自己公司项目时,都有机会遇到下面的错误:
UNEXPECTED TOP-LEVEL EXCEPTION:
没错,你的应用中的Dex文件方法数超过了65535的上限,简单的说,应用爆炸了。
那么让我们看一下为什么会引起这种错误:
在Android系统中,一个APP的所有代码都在一个Dex文件里面。Dex是一个类似Jar的存储了多个Java编译字节码的归档文件。因为Android系统使用Dalvik虚拟机,所以需要把使用Java Compiler编译之后的class文件转换成Dalvik能够执行的class文件。这里需要强调的是,Dex和Jar一样是一个归档文件,里面仍然是Java代码对应的字节码文件。当Android系统启动一个应用的时候,有一步是对Dex进行优化,这个过程有一个专门的工具来处理,叫DexOpt。DexOpt的执行过程是在第一次加载Dex文件的时候执行的。这个过程会生成一个ODEX文件,即Optimised Dex。执行ODex的效率会比直接执行Dex文件的效率要高很多。但是在早期的Android系统中,DexOpt有一个问题,也就是这篇文章想要说明并解决的问题。DexOpt会把每一个类的方法id检索起来,存在一个链表结构里面。但是这个链表的长度是用一个short类型来保存的,导致了方法id的数目不能够超过65536个。当一个项目足够大的时候,显然这个方法数的上限是不够的。尽管在新版本的Android系统中,DexOpt修复了这个问题,但是我们仍然需要对低版本的Android系统做兼容.
目前比较常用的方法:
(1) 应用插件化,比如使用我正在参与开发的插件化框架 : https://github.com/singwhatiwanna/dynamic-load-apk ,如果有建议或者相关的问题,欢迎到Github上积极参与.
(2) 分割Dex,多工程: 把所需要的.class文件或者是Jar文件和一些源码一起编译生成一个Jar文件。然后使用Android SDK提供的dx工具把Jar文件转成Dex文件。我们可以提前对它进行ODex操作,让它在被DexClassLoader加载的时候,跳过DexOpt的部分工作,从而加快加载的过程.(可参考facebook: https://www.facebook.com/notes/facebook-engineering/under-the-hood-dalvik-patch-for-facebook-for-android/10151345597798920,这里边还可以看到在2.3上动态改变LinearAlloc缓冲的解决思路) 这两种方法并不冲突,插件化除了解决应用爆棚,还有很多其他的优点,可以看我之前的文章,不再复述.
当然,Google看来也意识到了目前应用方法数爆棚的问题, 目前在已经在API 21中提供了通用的解决方案,那就是android-support-multidex.jar. 这个jar包最低可以支持到API 4的版本(Android L及以上版本会默认支持mutidex).
让我们看一下如何应用android-support-multidex.jar(以下都以在Anroid studio中的使用为例,使用eclipse开发需要安装gradle插件,其他基本上相同):
首先在app/build.gradle文件中配置,如下:
接下来的配置,有两种配置方式:
(1) : 在application的子类中配置(如果你需要有Application子类的情况)
(2) : 如果你不需要application的子类的情况,那就直接集成MultiDexApplication
好了,经过上面两步的解决,Android 65535的问题,也得到了解决。
使用MutiDex的注意事项:
一、如果你继承了MutiDexApplication或者覆写了Application中的attachBaseContext()方法。
Application类中的逻辑的注意事项:
Application中的静态全局变量会比MutiDex的instal()方法优先加载,所以建议避免在Application类中使用静态变量引用main classes.dex文件以外dex文件中的类,可以根据如下所示的方式进行修改:
二. 虽然Google解决了应用总方法数限制的问题,但并不意味着开发者可以任意扩大项目规模。Multidex仍有一些限制:
DEX文件安装到设备的过程非常复杂,如果第二个DEX文件太大,可能导致应用无响应。此时应该使用ProGuard减小DEX文件的大小。
由于Dalvik linearAlloc的Bug,应用可能无法在Android 4.0之前的版本启动,如果你的应用要支持这些版本就要多执行测试。
同样因为Dalvik linearAlloc的限制,如果请求大量内存可能导致崩溃。Dalvik linearAlloc是一个固定大小的缓冲区。在应用的安装过程中,系统会运行一个名为dexopt的程序为该应用在当前机型中运行做准备。dexopt使用LinearAlloc来存储应用的方法信息。Android 2.2和2.3的缓冲区只有5MB,Android 4.x提高到了8MB或16MB。当方法数量过多导致超出缓冲区大小时,会造成dexopt崩溃。
Multidex构建工具还不支持指定哪些类必须包含在首个DEX文件中,因此可能会导致某些类库(例如某个类库需要从原生代码访问Java代码)无法使用。
避免应用过大、方法过多仍然是Android开发者要注意的问题。Mihai Parparita的开源项目dex-method-counts可以用于统计APK中每个包的方法数量。
通常开发者自己的代码很难达到这样的方法数量限制,但随着第三方类库的加入,方法数就会迅速膨胀。因此选择合适的类库对Android开发者来说尤为重要。
开发者应该避免使用Google Guava这样的类库,它包含了13000多个方法。尽量使用专为移动应用设计的Lite/Android版本类库,或者使用小类库替换大类库,例如用Google-gson替换Jackson JSON。而对于Google Protocol Buffers这样的数据交换格式,其标准实现会自动生成大量的方法。采用Square Wire的实现则可以很好地解决此问题。
常见问题
问题1:DexException: Library dex files are not supported in multi-dex mode,你可能会见到如下的错误:
解决方法:对于dex 的--multi-dex 选项设置与预编译的library工程有冲突,因此如果你的应用中包含引用的lirary工程,需要将预编译设置为false:
问题2:OutOfMemoryError: Java heap space.当运行时如果看到如下错误:
解决方法:在dexOptions中有一个字段用来增加java堆内存大小:
参考相关资料:
1. MutiDex 官方文档: https://developer.android.com/reference/android/support/multidex/MultiDex.html
2. http://blog.osom.info/2014/10/multi-dex-to-rescue-from-infamous-65536.html
另附android -support-mutidex.jar下载地址: http://download.csdn.net/detail/t12x3456/8143383
Android 解决65535的限制(官网推荐方法)
http://blog.csdn.net/czhpxl007/article/details/50419974
相信大家在做自己公司项目时,都有机会遇到下面的错误:
UNEXPECTED TOP-LEVEL EXCEPTION:
java.lang.IllegalArgumentException: method ID not in [0, 0xffff]: 65536 at com.android.dx.merge.DexMerger$6.updateIndex(DexMerger.java:501) at com.android.dx.merge.DexMerger$IdMerger.mergeSorted(DexMerger.java:282) at com.android.dx.merge.DexMerger.mergeMethodIds(DexMerger.java:490) at com.android.dx.merge.DexMerger.mergeDexes(DexMerger.java:167) at com.android.dx.merge.DexMerger.merge(DexMerger.java:188) at com.android.dx.command.dexer.Main.mergeLibraryDexBuffers(Main.java:439) at com.android.dx.command.dexer.Main.runMonoDex(Main.java:287) at com.android.dx.command.dexer.Main.run(Main.java:230) at com.android.dx.command.dexer.Main.main(Main.java:199) at com.android.dx.command.Main.main(Main.java:103)
没错,你的应用中的Dex文件方法数超过了65535的上限,简单的说,应用爆炸了。
那么让我们看一下为什么会引起这种错误:
在Android系统中,一个APP的所有代码都在一个Dex文件里面。Dex是一个类似Jar的存储了多个Java编译字节码的归档文件。因为Android系统使用Dalvik虚拟机,所以需要把使用Java Compiler编译之后的class文件转换成Dalvik能够执行的class文件。这里需要强调的是,Dex和Jar一样是一个归档文件,里面仍然是Java代码对应的字节码文件。当Android系统启动一个应用的时候,有一步是对Dex进行优化,这个过程有一个专门的工具来处理,叫DexOpt。DexOpt的执行过程是在第一次加载Dex文件的时候执行的。这个过程会生成一个ODEX文件,即Optimised Dex。执行ODex的效率会比直接执行Dex文件的效率要高很多。但是在早期的Android系统中,DexOpt有一个问题,也就是这篇文章想要说明并解决的问题。DexOpt会把每一个类的方法id检索起来,存在一个链表结构里面。但是这个链表的长度是用一个short类型来保存的,导致了方法id的数目不能够超过65536个。当一个项目足够大的时候,显然这个方法数的上限是不够的。尽管在新版本的Android系统中,DexOpt修复了这个问题,但是我们仍然需要对低版本的Android系统做兼容.
目前比较常用的方法:
(1) 应用插件化,比如使用我正在参与开发的插件化框架 : https://github.com/singwhatiwanna/dynamic-load-apk ,如果有建议或者相关的问题,欢迎到Github上积极参与.
(2) 分割Dex,多工程: 把所需要的.class文件或者是Jar文件和一些源码一起编译生成一个Jar文件。然后使用Android SDK提供的dx工具把Jar文件转成Dex文件。我们可以提前对它进行ODex操作,让它在被DexClassLoader加载的时候,跳过DexOpt的部分工作,从而加快加载的过程.(可参考facebook: https://www.facebook.com/notes/facebook-engineering/under-the-hood-dalvik-patch-for-facebook-for-android/10151345597798920,这里边还可以看到在2.3上动态改变LinearAlloc缓冲的解决思路) 这两种方法并不冲突,插件化除了解决应用爆棚,还有很多其他的优点,可以看我之前的文章,不再复述.
当然,Google看来也意识到了目前应用方法数爆棚的问题, 目前在已经在API 21中提供了通用的解决方案,那就是android-support-multidex.jar. 这个jar包最低可以支持到API 4的版本(Android L及以上版本会默认支持mutidex).
让我们看一下如何应用android-support-multidex.jar(以下都以在Anroid studio中的使用为例,使用eclipse开发需要安装gradle插件,其他基本上相同):
首先在app/build.gradle文件中配置,如下:
android { compileSdkVersion 24 buildToolsVersion "24.0.1" defaultConfig { ... minSdkVersion 14 targetSdkVersion 24 ... // 设置支持multidex multiDexEnabled true } ... } dependencies { compile 'com.android.support:multidex:1.0.1' }
接下来的配置,有两种配置方式:
(1) : 在application的子类中配置(如果你需要有Application子类的情况)
package com.example; import android.app.Application; import android.content.Context; /** * */ public class MyApplication extends Application { @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); MultiDex.install(this); } }
(2) : 如果你不需要application的子类的情况,那就直接集成MultiDexApplication
package com.example; import android.support.multidex.MultiDexApplication; import android.content.Context; /** * Extended MultiDexApplication */ public class MyApplication extends MultiDexApplication { // 不需要重写attachBaseContext() //.......... }
好了,经过上面两步的解决,Android 65535的问题,也得到了解决。
使用MutiDex的注意事项:
一、如果你继承了MutiDexApplication或者覆写了Application中的attachBaseContext()方法。
Application类中的逻辑的注意事项:
Application中的静态全局变量会比MutiDex的instal()方法优先加载,所以建议避免在Application类中使用静态变量引用main classes.dex文件以外dex文件中的类,可以根据如下所示的方式进行修改:
@Override public void onCreate() { super.onCreate(); final Context mContext = this; new Runnable() { @Override public void run() { // put your logic here! // use the mContext instead of this here } }.run(); }
二. 虽然Google解决了应用总方法数限制的问题,但并不意味着开发者可以任意扩大项目规模。Multidex仍有一些限制:
DEX文件安装到设备的过程非常复杂,如果第二个DEX文件太大,可能导致应用无响应。此时应该使用ProGuard减小DEX文件的大小。
由于Dalvik linearAlloc的Bug,应用可能无法在Android 4.0之前的版本启动,如果你的应用要支持这些版本就要多执行测试。
同样因为Dalvik linearAlloc的限制,如果请求大量内存可能导致崩溃。Dalvik linearAlloc是一个固定大小的缓冲区。在应用的安装过程中,系统会运行一个名为dexopt的程序为该应用在当前机型中运行做准备。dexopt使用LinearAlloc来存储应用的方法信息。Android 2.2和2.3的缓冲区只有5MB,Android 4.x提高到了8MB或16MB。当方法数量过多导致超出缓冲区大小时,会造成dexopt崩溃。
Multidex构建工具还不支持指定哪些类必须包含在首个DEX文件中,因此可能会导致某些类库(例如某个类库需要从原生代码访问Java代码)无法使用。
避免应用过大、方法过多仍然是Android开发者要注意的问题。Mihai Parparita的开源项目dex-method-counts可以用于统计APK中每个包的方法数量。
通常开发者自己的代码很难达到这样的方法数量限制,但随着第三方类库的加入,方法数就会迅速膨胀。因此选择合适的类库对Android开发者来说尤为重要。
开发者应该避免使用Google Guava这样的类库,它包含了13000多个方法。尽量使用专为移动应用设计的Lite/Android版本类库,或者使用小类库替换大类库,例如用Google-gson替换Jackson JSON。而对于Google Protocol Buffers这样的数据交换格式,其标准实现会自动生成大量的方法。采用Square Wire的实现则可以很好地解决此问题。
常见问题
问题1:DexException: Library dex files are not supported in multi-dex mode,你可能会见到如下的错误:
Error:Execution failed for task ':app:dexDebug'. > com.android.ide.common.internal.LoggedErrorException: Failed to run command: $ANDROID_SDK/build-tools/android-4.4W/dx --dex --num-threads=4 --multi-dex ... Error Code: 2 Output: UNEXPECTED TOP-LEVEL EXCEPTION: com.android.dex.DexException: Library dex files are not supported in multi-dex mode at com.android.dx.command.dexer.Main.runMultiDex(Main.java:322) at com.android.dx.command.dexer.Main.run(Main.java:228) at com.android.dx.command.dexer.Main.main(Main.java:199) at com.android.dx.command.Main.main(Main.java:103)
解决方法:对于dex 的--multi-dex 选项设置与预编译的library工程有冲突,因此如果你的应用中包含引用的lirary工程,需要将预编译设置为false:
android { // ... dexOptions { preDexLibraries = false } }
问题2:OutOfMemoryError: Java heap space.当运行时如果看到如下错误:
UNEXPECTED TOP-LEVEL ERROR: java.lang.OutOfMemoryError: Java heap space
解决方法:在dexOptions中有一个字段用来增加java堆内存大小:
android { // ... dexOptions { javaMaxHeapSize "2g" } }
参考相关资料:
1. MutiDex 官方文档: https://developer.android.com/reference/android/support/multidex/MultiDex.html
2. http://blog.osom.info/2014/10/multi-dex-to-rescue-from-infamous-65536.html
另附android -support-mutidex.jar下载地址: http://download.csdn.net/detail/t12x3456/8143383
Android 解决65535的限制(官网推荐方法)
http://blog.csdn.net/czhpxl007/article/details/50419974
发表评论
-
某些android手机获取不到IMEI问题
2018-08-21 14:17 7637某些山寨机可能拿不到IMEI 如果非要IMEI可以模拟一个 ... -
APK安装成功后点击"打开"再按Home键应用会重启的问题
2018-08-21 14:13 2774安装系统SD卡里面的apk或者原有的程序更新版本的时候, ... -
使用volley链接Https地址时报SSLHandshakeException
2018-08-21 14:06 2142在真实设备上出现以下错误 ︰ Volley error: ... -
PhotoView+Viewpager双指缩放的时候出现pointerIndex out of range问题
2017-07-10 14:30 4248PhotoView+Viewpager开发图集效果的时候,在某 ... -
Android6.0权限封装
2017-04-01 12:04 1575简介 Android6.0中对权限分为了一般权限和危险权限。 ... -
实现点击 WebView 中的图片,调用原生控件展示图片
2017-04-01 11:14 2814现在有很多时候,我们的 App 都进行了混合开发,而最简单,最 ... -
android引用资源@与属性?备忘单
2017-03-30 10:09 1292几天前我偶然发现了我A ... -
ViewPager 与SwipeRefreshLayout,RecyclerView,ScrollView滑动冲突解决方法
2017-03-30 09:55 6571ViewPager 作为一个横向滚动的控件, 在 ViewGr ... -
Android中一些你可能没注意的小效果实现
2017-02-15 21:09 0http://www.see-source.com/blog/ ... -
Android热修复:Andfix和Hotfix,两种方案的比较与实现
2017-02-15 21:00 0http://www.see-source.com/blog/ ... -
Android 从网页中跳转到本地App
2017-01-11 09:27 1885我们在使用微信、QQ、京东等app的时候,会发现有时候通过他们 ... -
Activity的启动模式和onNewIntent
2016-12-28 09:10 1338一、启动模式介绍 启 ... -
android5.0使用Notification报RemoteServiceException的解决办法
2016-08-31 16:13 11554有时android5.0下使用Notification会报如下 ... -
RecyclerView 中的 item 如何居中问题
2016-05-18 09:52 12558一个很简单的Item布局,我只要让它由上而下排列,文字居中 ... -
sqlite3:not found 解决方法
2015-12-08 16:03 2559最最最重要,先root你的手机吧 sqlite3 为一个可 ... -
隐藏底部虚拟键NavigationBar实现全屏
2015-10-08 17:20 9858import android.app.Activity; ... -
服务端执行慢或网络延迟时,Volley多次发送请求的问题
2015-07-27 15:40 7004原文: Android Volley double post ... -
如何获取 Android 设备的CPU核数、时钟频率以及内存大小
2015-06-30 17:04 4389原帖: http://www.jianshu.com/p/f7 ... -
android点滴5
2015-04-10 17:32 2053一些小效果的实现 http://www.see-source. ... -
SwipeRefreshLayout和ListView的EmptyView共存冲突的问题
2015-01-20 11:47 18652SwipeRefreshLayout是android官方的下拉 ...
相关推荐
在Android应用开发中,开发者经常会遇到一个问题,那就是“65535...当应用中的方法数超过这个限制时,编译过程会抛出`DexIndexOverflowException`,错误信息可能类似于:“Error converting bytecode to dex: Cause: ...
`put`方法将图片与对应的键一起存入缓存,而`getSoftReference`和`getWeakReference`方法分别根据键获取软引用或弱引用的对象。当需要清理缓存时,只需要清空这两个映射即可,因为软引用和弱引用的对象会在垃圾收集...
本文将深入探讨如何使用JavaScript调用Android的方法,并传递JSON数据,以实现两者之间的高效通信。 首先,我们需要了解`Android WebView`。WebView是Android系统提供的一种组件,它能够加载并显示网页内容,就像是...
google提供了以下解决方案用的是原来HP的相关资料。 可以吧,这个迁移到Android上。 工程导入成功是可以正常运行的,我是专门换了个电脑重新验证了下。 如果有不能运行的问题,应该是其他方面的问题,不然我的截图...
7. **注意事项**:尽管multi-dex解决了方法数限制问题,但它也会增加应用的启动时间和内存消耗。因此,优化代码和避免无用库的引入仍然是最佳实践。 8. **Android 6.0及更高版本**:从Android 6.0 (API级别23)开始...
该Android水平数字滚动器,完全自定义,继承view,在界面中可以左右滚动一行很长的数据,可以并且选中屏幕中间的数字,中间的数字最大最大,两边数字变淡变小,可以根据个人需要调整字体和颜色,在实际项目开发中可以...
对于`res`目录下的资源,可以使用`android.resource://[package_name]/[resource_type]/[resource_id]`格式,但通常不推荐这种方法,因为资源会被编译为二进制格式,不适合直接用作URL。 另外,如果需要处理点击...
第二步:运行SDK Manager.exe 会生成temp的文件夹,(有同学找不到SDK Manager.exe,或找到了运行不了,解决:把SDK Manager.exe从\tools\lib目录下复制到SDK的根目录双击打开就OK了) 第三步:把SDK Manager.exe关...
Android之增长的数字动画
请注意,由于我们访问的是Android的内部类和私有方法,这种方法可能在不同的Android版本或设备上表现不一致,甚至可能在未来的Android更新中失效。因此,这种解决方案应当作为最后的手段,并且需要对可能的风险有所...
在Android开发过程中,由于Dalvik虚拟机对单个APK应用资源数量的限制,超过65535个方法可能会导致“方法数超限”错误。这个问题在早期的Android版本中尤为常见,尤其是在使用Eclipse作为开发环境时。不过,随着...
自定义view解决android文本排版和换行问题自定义view解决android文本排版和换行问题自定义view解决android文本排版和换行问题自定义view解决android文本排版和换行问题自定义view解决android文本排版和换行问题...
在Android开发中,自定义View是一项重要的技能,它允许开发者创造出独特且富有创新性的用户界面。本主题将深入探讨如何创建一个LED数字时钟的自定义View,这是一款结合了多个基本控件并以LED风格显示时间的组件。LED...
本文将深入探讨如何在Android中调用JavaScript的方法以及JavaScript如何反过来调用Android的本地方法。 首先,Android通过WebView组件提供了与JavaScript交互的能力。WebView是Android系统提供的一种用于加载和显示...
这通常被用在未读短信数提醒、待更新应用数提示等场景,提升用户体验,使用户一眼就能看到有多少未处理的内容。在本教程中,我们将深入探讨如何在Android应用中实现这一功能。 首先,我们需要了解Android的通知系统...
在项目中需要进行Fragment的切换,一直都是用replace()方法来替换Fragment 但是,这样会有一个问题 ,应该很多朋友都遇到过: 每次切换的时候,Fragment都会重新实例化,也就是运行OnCreatVIew()方法 那么如何让多个...
综上所述,解决Android ListView中多个EditText显示混乱的问题需要理解ListView的复用机制,并针对性地调整Adapter、EditText以及ListView的行为。结合提供的源码和示例,开发者可以更直观地学习和应用这些解决方案...
`android-support-v4`库中的`requestPermissions()`方法正是为了解决这个问题。 `requestPermissions()`是Android 6.0引入的一个关键函数,用于在运行时请求尚未被用户授权的权限。当应用需要使用某个敏感功能(如...
原因:Dalvik 的 invoke-kind 指令集中,method reference index 只留了 16 bits,最多能引用 65535 个方法。 参考=>由Android 65K方法数限制引发的思考. 解决: android{ defaultConfig { multiDexEnabled true...