Android 高效现实图片问题

1.为什么显示图片的问题很棘手?

手机显示一张800万像素的图片(现在主流的手机像素都是在800万像素以上),大约需要32M的内存,而32M内存刚好是Android系统分配给应用的最大内存限制数目,当然有的手机分配是的16M,有的甚至只有8M,这个根据手机的总共RAM与版本有一定得联系,所以如果手机中的应用打开一张这样的图片的话,基本上都会遇到内存泄露的问题,导致的内存严重不足,一般情况下将会导致应用被强制退出

以Galaxy Nexus 为例,前后置的相机的像素是500W,其分辨率是2592*1936 如果位图使用的ARGB_8888(在Android 2.3以上版本一般默认设置是这种图片的格式) 加载该位图将大概占用19M 的内存(2592*1936*4 byte),因此程序会很快耗尽内存为每个应用分配的内存,从而导致程序员崩溃

即使应用程序不一定非得显示一张500W像素的图片,但是当在ListView,GridView中显示大量的图片,并且图片没有来得及回收的情况下,同事所占用的内存将是每张图片的总和,如果不对图片进行处理,将一样的会出现程序员因内存不足而强制退出

2.如何解决图片显示导致内存溢出的问题?

要解决图片显示导致内存的溢出,得考虑5个问题:

2.1如何高效的加载大位图

2.2如何在非UI线程中处理位图

2.3如何对位图进行缓存

2.4如何管理位图内存

2.5如何在Ui中显示位图

3.如何高效加载大位图

3.1获取位置以及尺寸

使用BitmaoFactory对位图进行解码的时候,使用BitmapFactory.Options ,将Options的injusDecodeBounds设为true时,可以避免为位图分配内存,此时的BitmapFactory.decdeX将返回null,但是会为Options设置outWidth,outHeight,outMemiType值

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;
通过上述的代码你就可以在不为位图分配内存的情况下,获取位图的高与宽与位图的类型,之后在显示图片的时候,就可以通过获取的信息来判断是否需要对图片进行出来之后再显示,从未避免内存溢出的问题

3.2将缩小的图片加载到内存

如果仅仅需要对128*96的图片缩略图进行显示,而将一张原始大小为1024*768的图片加载到内存,就显得很不划算,因此对图片进行压缩之后再显示就很有必要了,因此对图片按照比例缩小再进行显示就显得很有必要了

通过设置Option.insampleSize来产生缩小之后的图片,例如Option.insampleSize=4,那么一张原始大小为2048*1536的位图来说,产生的新位图的大小约为512*384,将这么大的位图加载到内存却只需要0.75M 的内存,而原图片却需要大概12M的内存

具体程序实现如下,将injustDecodeBounds设置为ture获取到位图信息,然后再设置insampleSize的值,然后再将injustDecodeBounds设置为false,从而将新产生的位图加载到内存

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

上述方法使用calculateInSampleSize方法实现如下:


public static int calculateInSampleSize(
            BitmapFactory.Options options, int reqWidth, int reqHeight) {
    // Raw height and width of image
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {

        // Calculate ratios of height and width to requested height and width
        final int heightRatio = Math.round((float) height / (float) reqHeight);
        final int widthRatio = Math.round((float) width / (float) reqWidth);

        // Choose the smallest ratio as inSampleSize value, this will guarantee
        // a final image with both dimensions larger than or equal to the
        // requested height and width.
        inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
    }

    return inSampleSize;
}

需要注意的是上述返回的InSampleSize的值最好是2的N次幂

综上所述有了上述的方法,我们就可以在程序中,加载任意大小的图片,而不用担心内存溢出的问题,例如下面的代码将会把图片设置成100*100像素的缩略图:

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

转载自:http://yhz61010.iteye.com/blog/1848337

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值