一、为什么Bitmap需要高效加载?
现在的高清大图,动辄就要好几M,而Android对单个应用所施加的内存限制,只有
小几十M,如16M,这导致加载Bitmap
的时候很容易出现内存溢出。如下异常信
息,便是在开发中经常需要的:
java.lang.OutofMemoryError:bitmap size exceeds VM budget
为了解决这个问题,就出现了Bitmap的高效加载策略。其实核心思想很简单。假设
通过ImageView
来显示图片,很多时候ImageView
并没有原始图片的尺寸那么大,
这个时候把整个图片加载进来后再设置给ImageView
,显然是没有必要的,因为ImageView
根本没办法显示原始图片。这时候就可以按一定的采样率来将图片缩小
后再加载进来,这样图片既能在ImageView
显示出来,又能降低内存占用从而在一
定程度上避免OOM
,提高了Bitmap
加载时的性能
二、Bitmap高效加载的具体方式
1.加载Bitmap的方式
Bitmap在Android中指的是一张图片。通过BitmapFactory类提供的四类方法:decodeFile
,decodeResource
,decodeStream
和decodeByteArray
,分别从文件系统,
资源,输入流和字节数组中加载出一个Bitmap对象,其中decodeFile,decodeResource
又间接调用了decodeStream
方法,这四类方法最终是
在Android的底层实现的,对应着BitmapFactory
类的几个native方法。
2.BitmapFactory.Options
的参数
①inSampleSize
参数
上述四类方法都支持BitmapFactory.Options
参数,而Bitmap
的按一定采样率进行缩
放就是通过BitmapFactory.Options
参数实现的,主要用到了inSampleSize
参数,即
采样率。通过对inSampleSize
的设置,对图片的像素的高和宽进行缩放。
当inSampleSize=1
,即采样后的图片大小为图片的原始大小。小于1,也按照1来计
算。 当inSampleSize>1
,即采样后的图片将会缩小,缩放比例为1/(inSampleSize
的二次方)。
例如: 一张1024 ×1024像素的图片,采用ARGB8888格式存储,那么内存大小
1024×1024×4=4M。如果inSampleSize=2
,那么采样后的图片内存大小:
512×512×4=1M。
注意: 官方文档支出,inSampleSize
的取值应该总是2的指数,如1,2,4,8等。
如果外界传入的inSampleSize
的值不为2的指数,那么系统会向下取整并选择一个
最接近2的指数来代替。比如3,系统会选择2来代替。当时经验证明并非在所有
Android版本上都成立。
关于inSampleSize
取值的注意事项: 通常是根据图片宽高实际的大小/需要的宽高
大小,分别计算出宽和高的缩放比。但应该取其中最小的缩放比,避免缩放图片太
小,到达指定控件中不能铺满,需要拉伸从而导致模糊。
例如: ImageView
的大小是100×100像素,而图片的原始大小为200×300,那么宽
的缩放比是2,高的缩放比是3。如果最终inSampleSize=2
,那么缩放后的图片大小
100×150,仍然合适ImageView
。如果inSampleSize=3
,那么缩放后的图片大小小
于ImageView
所期望的大小,这样图片就会被拉伸而导致模糊。
②inJustDecodeBounds
参数
我们需要获取加载的图片的宽高信息,然后交给inSampleSize
参数选择缩放比缩
放。那么如何能先不加载图片却能获得图片的宽高信息,通过inJustDecodeBounds=true
,然后加载图片就可以实现只解析图片的宽高信息,并
不会真正的加载图片,所以这个操作是轻量级的。当获取了宽高信息,计算出缩放
比后,然后在将inJustDecodeBounds=false
,再重新加载图片,就可以加载缩放后
的图片。
注意: BitmapFactory
获取的图片宽高信息和图片的位置以及程序运行的设备有
关,比如同一张图片放在不同的drawable
目录下或者程序运行在不同屏幕密度的设
备上,都可能导致BitmapFactory
获取到不同的结果,和Android的资源加载机制
有关
3.高效加载Bitmap
的流程
①将BitmapFactory.Options
的inJustDecodeBounds
参数设为true并加载图片。
②从BitmapFactory.Options
中取出图片的原始宽高信息,它们对应于outWidth
和outHeight
参数。
③根据采样率的规则并结合目标View的所需大小计算出采样率inSampleSize
。
④将BitmapFactory.Options
的inJustDecodeBounds
参数设为false,然后重新加载
图片。
三、Bitmap
高效加载的代码实现
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight){
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
//加载图片
BitmapFactory.decodeResource(res,resId,options);
//计算缩放比
options.inSampleSize = calculateInSampleSize(options,reqHeight,reqWidth);
//重新加载图片
options.inJustDecodeBounds =false;
return BitmapFactory.decodeResource(res,resId,options);
}
private static int calculateInSampleSize(BitmapFactory.Options options, int reqHeight, int reqWidth) {
int height = options.outHeight;
int width = options.outWidth;
int inSampleSize = 1;
if(height>reqHeight||width>reqWidth){
int halfHeight = height/2;
int halfWidth = width/2;
//计算缩放比,是2的指数
while((halfHeight/inSampleSize)>=reqHeight&&(halfWidth/inSampleSize)>=reqWidth){
inSampleSize*=2;
}
}
return inSampleSize;
}
这个时候就可以通过如下方式高效加载图片:
mImageView.setImageBitmap(decodeSampledBitmapFromResource(getResources(),R.mipmap.ic_launcher,100,100);
除了BitmapFactory
的decodeResource
方法,其他方法也可以类似实现。
更多内容详情请关注我的GitHub:https://github.com/xiangjiana/Android-MS
相关推荐
`compressBitmapToStream(Bitmap bitmap, OutputStream stream)`方法可以将Bitmap压缩后写入OutputStream,避免一次性加载整个图片到内存。 6. **优化缓存策略**: 在Android应用中,内存缓存和磁盘缓存是必不可少...
本示例将详细介绍Android中Bitmap的处理,包括图片缓存策略和加载大图的技巧。 1. **Bitmap的内存管理** - **内存分配**:Bitmap对象会根据其像素宽度、高度和颜色格式占用不同的内存。例如,一个2000x1500像素的...
在TestCompressBitmap项目中,你可以找到更多关于Bitmap压缩的实践案例,包括不同方法的比较,以及在实际应用中的性能优化策略。通过这些示例,你可以更好地理解如何根据应用场景选择合适的压缩策略,确保图片质量与...
本篇文章将深入探讨Android Bitmap的压缩方法,特别是如何选择合适的压缩策略以适应不同的场景需求,特别是在处理分享到社交平台如微信时的32KB大小限制。 首先,我们来看一下问题的背景:在测试过程中,发现将文章...
- **Bitmap的缓存策略**:实现LRU(Least Recently Used)缓存,提高图片加载速度,减少内存开销。 - **图片压缩**:除了上述的JPEG/PNG压缩,还可以使用WebP等高效格式进行压缩。 - **图片质量检测**:计算图片的...
在Android开发中,Bitmap对象是用于处理图像的主要类,但如果不正确管理,它可能导致应用程序运行时出现`OutOfMemoryError`。这是因为Bitmap占用大量的内存,尤其是当加载大尺寸或高分辨率图片时。这个问题在低内存...
在Android开发中,有时我们需要将Bitmap对象转换成不同的图片格式,比如BMP。BMP(Bitmap File Format)是一种常见的位图文件格式,但它并不像JPEG或PNG那样被Android SDK直接支持。本文将详细介绍如何在Android中将...
3. **Bitmap压缩(CompressBitmap)**:Bitmap是Android中用于处理图像的基本类,但其内存占用较高。`CompressHelper`提供了压缩Bitmap的方法,这在处理大量图片或者内存受限的设备上非常有用。它可以调整Bitmap的...
文档标题和描述中提到的“ANDROIDBITMAP内存限制OOM,OUTOFMEMORY”指的就是在处理位图(BITMAP)时超出了虚拟机(VM)的内存预算,导致系统抛出OutOfMemoryError异常。 根据给出的内容部分,我们可以推断出以下知识...
以上两种方法都是Android中常见的图片压缩策略,可以根据实际需求选择合适的方式。质量压缩适用于对图片质量要求较高,但希望控制图片大小的情况;比例大小压缩则适用于加载大图时,以避免内存问题。在实际应用中,...
本文将深入探讨Android Bitmap的压缩策略。 首先,Bitmap的压缩分为两种类型:质量压缩和尺寸压缩。质量压缩主要针对图片的质量,不改变图片的实际尺寸,而是降低颜色深度或使用有损压缩算法,以减小文件大小。尺寸...
总的来说,这个示例源代码将引导开发者学习如何在Android中有效地处理网络图片,包括下载、解码、缩放、压缩等关键环节,以及如何进行内存管理和优化策略的实施。这对于初级开发者来说,是一份宝贵的实践教程。通过...
可以使用`Bitmap.compress(Bitmap.CompressFormat, quality, stream)`方法将Bitmap压缩为JPEG或PNG格式的流。 总结,"bitmap上传图片demo"是一个综合性的实例,涵盖了Bitmap的加载、显示、裁剪和上传等多个环节,...
- 压缩图片:在将Bitmap保存到存储前,先进行压缩,减少存储消耗。 2. Bitmap.recycle()方法什么时候会回收内存? - Bitmap加载到内存后,内存分为Java部分和C部分。Java部分由虚拟机管理,不使用时自动回收。C...
7. **Android Bitmap压缩策略**:掌握如何减少Bitmap占用内存。 8. **Android动画总结**:了解视图动画、属性动画、动画资源的使用。 9. **Android进程优先级**:了解Android如何管理多个进程的优先级。 10. **...
在Android中,我们可以使用`Bitmap.compress()`方法,传入`Bitmap.CompressFormat.JPEG`或`Bitmap.CompressFormat.PNG`,并设置一个0到100之间的压缩质量值。值越低,压缩程度越大,文件大小越小,但可能会导致图像...
在实际应用中,开发者可以根据需求和场景选择合适的压缩策略。例如,如果需要在网络上传输图片,质量压缩更适合;如果希望在本地存储大量图片,采样率压缩可能更为合适。同时,要注意压缩与图片质量的平衡,过度压缩...
在这个测试工程中,开发者可以实践如何从资源文件加载Bitmap,然后进行压缩,并观察压缩前后内存和文件大小的变化,以评估不同压缩策略的效果。 总之,这个压缩bitmap测试工程提供了一个实践平台,帮助开发者掌握...
在实现高度自定义的图片压缩时,除了尺寸调整外,还可以考虑添加其他优化策略,如根据设备的屏幕密度选择不同的压缩级别,或者使用LruCache等内存缓存机制来存储压缩后的图片,减少不必要的重复压缩操作。...
Luban 自动选择合适的压缩策略,支持预览压缩效果,并能处理多种图片格式。使用Luban可以大大简化代码,提高开发效率。 4. **Glide或Picasso**:这两个都是流行的图片加载库,它们在加载图片时提供了内置的压缩功能...