问题描述
最近在项目中遇到一个奇葩的Crash,在创建bitmap时Crash,log如下:
一开始以为是OOM导致的Bitmap创建失败,后来查看了下当前的内存状态,并非OOM导致的,同时发现Crash全部分布在API <= 19的设备中。于是看了下源码,发现是因为资源图片导致的。
问题原因
首先看Crash代码
http://androidxref.com/4.0.4/xref/frameworks/base/graphics/java/android/graphics/Bitmap.java#601
Crash是因为bitmap的宽或者高为0了。
再看出问题的代码
http://androidxref.com/4.0.4/xref/frameworks/base/graphics/java/android/graphics/BitmapFactory.java#502
以上是在创建bitmap后根据当前设备的density对bitmap进行缩放的代码,同时只会当inTargetDensity和inDensity不一致时才执行,其中inTargetDensity也就是当前手机的density,而inDensity就是Bitmap的density。
举例说:
假如图片放在xhdpi下,那么bitmap的density就是320,xxhdpi,bitmap的density就是480。而如果当程序运行在density为120的手机上时,如果没有ldpi的图片,那么就会去取最接近的,假如这时取xhdpi的图片,那么inTargetDensity=120, inDensity=320, 这时
可以查看width计算结果为0,从而抛出异常。
以上只是api<=19的情况,在api19及以上,createBitmap以及缩放的代码全部放在了native中进行,但是当遇到上面的case时,虽然不会crash,但是得到的bitmap size为0,在绘制的时候显示为一片黑色。
解决方式
很简单,不使用1px的图片就行,同理,不仅在xhdpi中会出问题,在xxhdpi中也会出问题,只要上面的计算得到0都会crash.
因此有条简单的规则就是xhpdi和xxhdpi下都不能使用<=1px的图片,xxxhdpi下不能使用<=2px的图片。