今天给大家分享一些图片处理常用技术方案,Android应用开发的朋友必须要了解呀!
众所周知在Android应用开发中在对图片处理时,稍有不慎就会出现以下异常:
java.lang.OutofMemoryError: bitmap size exceeds VM budget.
以下几点是加载Bitmap时需要谨慎对待的原因:
-
通常移动设备的系统资源有限,Android设备会给每个应用分配16M的内存空间。 Android的兼容性定义文件(CDD)中第3.7节。提供了虚拟机的兼容性所需的各种屏幕尺寸和密度及最低的应用程序的内存。优化应用程序应参考这个最小的内存限制。然而,许多厂商的Android设备的系统会较高的限制配置。
-
Bitmap会占用大量的内存,尤其是带有丰富的图像的应用,像照片管理等应用。例如, 在Galaxy Nexus相机拍照的最高的为2592x1936像素(5百万像素)。如果使用bitmap 配置是ARGB_8888(默认从Android2.3起),那么这个图片加载到内存需要大约19MB的内存(2592*1936*4个字节),在某些设备上会立即耗尽应用程序的内存导致异常发生。
-
Android应用程序UI的经常需要一次加载多个图片。如在ListView,GridView和ViewPager中,通常在一屏中包括在多张图片。
如何高效的加载图片
图片尺寸与大小各种各样。多数情况下大于用户要在应用中使用的图片大小。例如:系统的Gallery应用中管理相机拍的照片时 , 照片的尺寸像素往往大于屏幕的密度。
基于内存限制的原因,理想情况下你需要加载低分辨率的图片到内存中。低分辨率的图片与UI控件的大小保持一致即可,高分辨率的图片对用户来说并不明显,然而对图片进行缩放操作也会占用宝贵的内存和额外的性能开销。
今天给大家分享一下如何不占用内存空间情况下对图片进行缩放采样。
读取Bitmap 的尺寸与类型
BitmapFactory类提高多种方法(decodeByteArray(), decodeFile(), decodeResource(), 等等)用来从不同资源文件中加载图片。根据图片资源类型选择相应的方法进行加载,这些方法在构造Bitmap对象时会费配内存,因此很容易导致OutOfMemory异常,你可以通过 BitmapFactory.Options类为不同解码方式参数;设置inJustDecodeBounds 为true是可以避免内存分配,结果为Null,但是附带了outWidth, outHeight and outMimeType.信息。通过这种方式你就可以在构在Bitmap对象前获取它的尺寸/类型信息
BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(getResources(), R.id.myimage, options); int imageHeight = options.outHeight; int imageWidth = options.outWidth; String imageType = options.outMimeType;
在使用图片前一定要检查图片的尺寸以避免内存溢出,除非你却定使用的图片尺寸合适且不会耗费过多的内存。
如何加载缩放的图片到内存中
现在你已经知道如何获取图片的大小了,这样在使用图片时你就可以决定是加载原图还是加载缩放的图片了,以下几点需要注意:
-
估算一下原图的内存使用情况
-
你的应用中允许分配给图片的内存大小
-
使用图片的ImageView或其他UI组件大小。
-
使用设备的屏幕大小与密度
例如:1024*768的图片实际上只需要在ImageView中显示128*96的缩略图
在BitmapFactory.Options 中设置inSampleSize为合适的采样率,以获取合适尺寸的图片。
例如:2048*1536的图片将 inSampleSize 位置为 4时可以得到512*384的图片,如果加载的内存中为0.75M,远低于原图的12M内存空间(Bitmap设置为ARGB_8888时),下面是一个基于需要的图片大小获取合适采样率例子:
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) { // First decode with inJustDecodeBounds=true to check dimensions final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(res, resId, options); // Calculate inSampleSize options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // Decode bitmap with inSampleSize set options.inJustDecodeBounds = false; return BitmapFactory.decodeResource(res, resId, options); }
通过上面的方法可以很容易的把一个大图片以100*100的缩略图的大小设置到ImageView中,例子如下:
mImageView.setImageBitmap( decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));
你可以参考上面的方式选择你需要的加载方式加载图片。