AndroidTrainingCHS -- 高效显示Bitmap

本文主要介绍一些通用的处理和加载Bitmap对象的方法.这些技术可以使的应用的UI更加流程并且避免消耗过多的内存.如果不注意这些,Bitmaps会迅速消耗应用内存进而导致程序Crash.


错误 : java.long.OutofMemoryError : bitmap size exceeds VM budget.

    图片有不同的形状和大小.在大多数情况下他们的实际尺寸都比需要呈现的尺寸要大很多.考虑到程序是在有限的内存下工作.理想情况是只需要在内存中加载一个低分辨率的图片即可.

Bitmap类提供了一系列decode方法(decodeByteArray(),decodeFile(),decodeResource(),etc)用来从不同的资源中创建一个Bitmap对象 . APIs 如下 : 

 

根据你的图片数据源来选择合适的decode方法,那些方法在构造位图时会尝试分配内存,因此容易导致OutOfMemory的异常 . 每一种decode方法都提供了通过BitmapFactory.Options来设置一些标记来指定decode 的选项. 设置 inJustDecodeBounds 属性为 true 可以在decoding的时候避免内存分配 , 他会返回一个null的bitmap对象,但是outWidth,outHeight与outMimeType还是可以获取到的 . 这种技术允许你在构造bitmap之前获取图片的尺寸和类型.

获取到图片的的实际尺寸后可以结合我们需要显示的尺寸来及算出缩放比例 . BitmapFactory.Options 对象的inSampleSize 变量就是表示加载图片时的缩放比例 . 如此一来我们就可以按照我们的需求来加载一个降低分辨率后 的图片 , 节省不必要的内存开销. 同时可以在很大程度上避免OutofMemory错误.

inSampleSize 解析:

inSampleSize 是一个用来表示加载图像缩放比例的 int 类型的值 , Android系统对于它的处理分以下两种情况 :

(1)  inSampleSize > 1 时 :

加载图片时会对图片进行二次采样(修改加载图片尺寸) , inSampleSize 大小是在解码位图中对应于尺寸中长度 / 宽度的缩放比例。例如 , inSampleSize = 4 返回的图片的长度 和 宽度上的像素数量都将会变为原来的四分之一(1/4) . 整个图片的像素数时实际图片像素数的十六分之一(1/(4 * 4)) . 对应尺寸关系如下 

假设 inSampleSize = 4. 则有如下关系 :

A.  加载图片的长度 =  图片真实长度 / 4;

B.  加载图片的宽度 =  图片真实长度 / 4;

C.  加载图片的尺寸 =  图片真实尺寸 / 16;

(2) inSampleSize <= 1 时 :

对于这种情况Android系统会将inSampleSize当做1对待 .

注意 : inSampleSize 都是2 的幂 如果设置的不是2 的幂则系统会用最接近它值得2 的次幂来代替.

inJustDecodeBounds 解析 :

inJustDecodeBounds 是一个表示是否为图片分配内存的布尔值 .因此可以利用此标记获取图片尺寸.

     (1)  inJustDecodeBounds = true : decoder 加载图片时不会再内存中分配空间 , 返回一个null对象.但是回返回图       片的真实尺寸和类型(在BitmapFactory.Options对象中).

        (2)  inJustDecodeBounds = false : decoder 加载图片时会为Bitmap分配内存.

计算图片缩放比例代码:

/**
* 计算图片缩放比例
* @param options    Options 对象
* @param reqWidth   显示的宽度
* @param reqHeight  显示的高度
* @return
*      缩放比例 : 宽高都会缩放inSampleSize. 
*/
public static int calculateInSampleSize(BitmapFactory.Options options,int reqWidth,int reqHeight){
    // 获取图片的实际尺寸
    final int height = options.outHeight;
    final int width = options.outWidth;
    // 初始缩放比为 1,即不进行缩放.
    int inSampleSize = 1;
    // 计算缩放比.
    if (height > reqHeight || width > reqWidth){
        final int halfH = height / 2;
        final int halfW = width / 2;
        while((halfH / inSampleSize) > reqHeight && (halfW / inSampleSize) > reqWidth){
            inSampleSize *= 2;
        }
    }
    return inSampleSize;
}

加载指定大小的图片到内存中 :

/**
* 加载指定大小的图片
* @param res         资源
* @param resId       资源id
* @param reqWidth    显示宽度
* @param reqHeight   显示高度
* @return
*      处理后的图片
*/
public static Bitmap decodeSampledBitmapFromResource(Resources res,int resId,int reqWidth,int reqHeight){
    // 1. 获取实际尺寸
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(res,resId,options);
    // 2. 计算 inSampleSize
    options.inSampleSize = calculateInSampleSize(options,reqWidth,reqHeight);

    // 3. 加载缩放后的图片
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeResource(res,resId,options);
}
























评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值