Android如何高效的加载图片(1)---加载大尺寸图片

xiaoxiao2021-02-28  74

完美的去加载bitamap,不但可以增加用户体验度,还能避免内存溢出。加载bitmap,一部小心就会导致应用crash.报出下面的异常。

java.lang.OutofMemoryError: bitmap size exceeds VM budget.

如果需要加载图片比较大。很容易造成内存溢出,如何去防止内存溢出呢。

读取bitmap的尺寸和类型

BitmapFactory类提供了很多decoding方法(decodeByteArray(), decodeFile(), decodeResource()等)去加载bitmap从不同的数据源,根据图片的来源去选择合适的方法。这些方法在会占用很多内存去构造bitmap,因此,容易导致oom异常。我们如何去避免OOM异常呢。 每个方法有BitmapFactory.Options类,这个类中有个成员变量为inJustDecodeBounds,当我们设置它为true时,再去加载图片,则会避免OOM。这样做后,返回的bitmap为null。但是会返回图片的outWidth, outHeight 和outMimeType。那大家就疑惑了,我们就是为了创建bitmap,而现在返回的bitmap为null,有何用。其实这个就是为了在创建bitmap前获取图片的尺寸和类型。 为了避免OOM,在创建bitmap前,我们先去检查它的尺寸,除非,你绝对的有把握,现在app的内存完全足够去加载你想要decode的图片。 下面是获取图片尺寸和类型的代码:

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;

###加载缩放后图片到内存 现在,我们获取到了图片的尺寸,我们就可以知道我们是直接加载原图到内存,还是缩放后再去加载。 距离来说:现在有张1024x768像素的图片,但是我们最终只需要展示一张128x96是像素缩略图即可。

现在有张图片,原图大小为2048x1536,通过inSampleSize设置缩放4倍后,图片大小为512x384,加载原图需要12MB(假设图片的配置为ARGB_8888),而加载缩放后的图片需要0.75MB。下面这个方法就是的来计算缩放比例:

public static int calculateInSampleSize( BitmapFactory.Options options, int reqWidth, int reqHeight) { // 原图的宽高 final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { final int halfHeight = height / 2; final int halfWidth = width / 2; // Calculate the largest inSampleSize value that is a power of 2 and keeps both // height and width larger than the requested height and width. while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) { inSampleSize *= 2; } } return inSampleSize; }

我们发现上面的代码中计算缩放比取值用2的倍数。因为最终构建bitmap时,取值为2的倍数,舍尾。

利用上面这个方法,首先设置inJustDecodeBounds为true,获取到缩放比inSampleSize 的值后,再设置inJustDecodeBounds为false,最终利用bitmapFactory类中的方法去获取bitmap. 下面为获取bitmap的完整过程。

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); }

利用上面的方法,如果现在我们的需求为加载一张100x100的缩略图到ImageView中。代码为下:

mImageView.setImageBitmap( decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));

可以看到,经过以上的封装,我们可以非常容易的去加载任意尺寸的图片。

欢迎阅读下一篇Android中Bitmaps 处理详解(2)—在ui线程中处理Bitmaps

转载请注明原文地址: https://www.6miu.com/read-60507.html

最新回复(0)