标签:bitmap
相信大家在平时进行Android的开发过程中,都有使用过Bitmap。
其实Google自己也有一个简单介绍Bitmap如何使用的文章,Manage Bitmap Memory。在这里对一些简单的Bitmap内存优化做了介绍。
其实我写这篇文章的初衷是由于最近在写一个涉及到很多张Bitmap显示的控件,但是由于图片过多,假如完全显示会导致OOM,因此需要建立了一个图片缓存,
现在我手上有800多张136px*128px大小的图片,我现在分别通过将图片放在磁盘文件,assets目录,drawable的各个目录下,来测试通过BitmapFactory创建图片的性能。
测试平台为:Genymotion 模拟机上的 Preview-GoogleNexus6-5.1.0-API22-1440x2560。
对图片混存的最大限制为当前应用程序的 1/8 最大内存。
具体读取Bitmap的代码就不再放上来了,反正就是使用BitmapFactory的一些方法去读取,也挺简单的。
测试结果如下:
性能点 | File | Assets | drawable | drawable-ldpi | drawable-mdpi |
---|---|---|---|---|---|
读取时间总耗时 | 1360 | 406 | 2550 | 4100 | 2545 |
相同内存最大图片数 | 181 | 181 | 15 | 9 | 15 |
生成图片尺寸 | 136*128 | 136*128 | 476*448 | 635*597 | 476*448 |
drawalbe-hdpi | drawable-xhdpi | drawable-xxhdpi | drawable-xxxhdpi | ||
读取时间总耗时 | 1479 | 1132 | 940 | 619 | |
相同内存最大图片数 | 34 | 60 | 134 | 237 | |
生成图片尺寸 | 317*299 | 238*224 | 159*149 | 119*112 |
从上表中可以看出,对于同一套图片而言,从file,assets以及drawable下所取出的大小内存,以及消耗时间均不相同,总的来说从Assets目录下获取速度最快,消耗的内存相对较少。
而从drawable各目录下取出的图片随着屏幕像素的递减,其尺寸越大,占用内存越大,读取耗时越多。
我们仔细观察BitmapFactory中各个方法,我们会发现,不论是decodeResource ,decodeFile,他们最后都会调用decodeStream这个方法来获取Bitmap对象。
对于从文件和assets对象中获取bitmap而言,他们之间唯一的区别就是一个是从本地磁盘上读取,一个是从assets中读取,那么对一个应用而言,读取自身的速度会快一些,我们也可以理解。
而对于drawable目录里的图片而言,为什么他们读取出来的图片尺寸会不一样呢?
我记得在Android开发者官网上,Google曾经说过
If your application’s minSdkVersion is 4 or greater, you do not need default drawable resources when you provide alternative drawable resources with the screen density qualifier. Even without default drawable resources, Android can find the best match among the alternative screen densities and scale the bitmaps as necessary. However, for the best experience on all types of devices, you should provide alternative drawables for all three types of density.
这句话的大概意思就是对于最低sdk版本为4的应用而言,假如我们在某一个drawable路径下已经提供了一个drawable资源,那我们就不需要在默认的drawable目录下提供默认资源(要知道类似于values,layout这些xml文件,必须要有一个默认的配置项,而drawable只要你有一个就够了)。Android系统会自动找到最匹配的想,然后对找到的bitmap进行缩放,以供使用。
因此我们可以推断出之所以放置在各个drawable目录下导致生成的bitmap尺寸不同就是因为Android系统为我们进行了自动缩放。
接下来我们来看看Android是如何实现bitmap资源自动缩放的。
先从Java层的代码入手,我们发现在BitmapFactory中,decodeResource获取Bitmap的代码如下:
final TypedValue value = new TypedValue();
is = res.openRawResource(id, value);
bm = decodeResourceStream(res, value, is, null, opts);
在deoceResourceStream中代码如下:
if (opts.inDensity == 0 && value != null) {
final int density = value.density;
if (density == TypedValue.DENSITY_DEFAULT) {
opts.inDensity = DisplayMetrics.DENSITY_DEFAULT;
} else if (density != TypedValue.DENSITY_NONE) {
opts.inDensity = density;
}
}
if (opts.inTargetDensity == 0 && res != null) {
opts.inTargetDensity = res.getDisplayMetrics().densityDpi;
}
return decodeStream(is, pad, opts);
在这里我们也可看出来,Android首先从TypeValue中获取到了最匹配的drawable对象的屏幕像素密度,然后将drawable对象的屏幕像素同设备自身的屏幕像素密度传入opts对象中,再调取decodeStream方法,进行最后的bitmap解析。
因此Android通过BitmapFactory解析drawable中的图片文件时其实会按照图片所处文件夹的图片像素密度同现有设备的像素密度进行缩放。
根据bitmap的定义,长宽尺寸越大,其占用内存也会成平方级数的增长,因此就会发现对于同一张图片,放置图片的drawable文件夹的屏幕像素越低,其在同一设备上占用的内存就会越大。(Ps:真实使用的时候,放置在不同drawable文件夹下的相同图片的尺寸也必定不同,故这其实没有什么大问题。)
使用BitmapFactory不同方法解析Bitmap的简单分析
标签:bitmap
原文地址:http://blog.csdn.net/kifile/article/details/45934083