高效的加载图片1.缩放大容量的Bitmap

我们通过眼睛来观察世界,眼睛通过光的反射,折射将世间的万物映射到我们

的眼睛里。至于是在眼睛里生成图片传递给大脑,还是眼睛将映射得来的
这些图片,了解了世界。
图片何其重要,几乎每一个app都需要加载图片,然而并不是每一个app
都很好的加载了图片。
图片是什么,我们先说一下图片的属性:形状,大小,颜色。
这一节里我们讨论的是图片最简单的属性:大小。
每一部安卓手机对于加载图片使用的内存都是有限制的,据我所知,通常
的都是16MB。然而,就像世界上没有一模一样的叶子一样。图片也是多种
多样的,它们大小不一,形状各异。那么如果超过16MB会发生什么错误呢
你的手机够旧,配置够低,那么很容易的就会报Out of memory的异常,也就是一些人讲的OOM异常。
也许你会发现你的图片并没有超过16MB啊,为何还是报错,那是因为手
机在加载图片的时候需要的内存可能会比图片本身大,(这应该是涉及到图
片的复杂程度吧)。
如何避免OOM异常呢,手机内存的限制通过软件是无法改变的,那么我
们只好在图片本身上下文章。图片并不是一成不变的,只要我们能通过一定
的比例缩放图片就不需要那么大的内存了。一句话概括就是我们要尽量不破
坏原图表达的信息的基础上减小加载图片所需要的内存。而BitmapFactory.Options这个类就是为此而生的。

    package com.example.loadbigbitmap;

import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

public class ImageUtil {
    /**
     * 
     * @param options
     *            根据原图获得的options,通过它可以获得原图的高,宽,类型。因为inJustDecodeBounds设置成true了,
     *            所以并不会真的解码生成一个bitmap,也就不存在占用内存的问题了。
     * @param reqWidth 要求的宽
     * @param reqHeight 要求的高
     * @return 返回设置好的inSampleSize。
     */
    /*
     * 根据原图的高度和宽度和要求的高度和宽度计算出inSampleSize的大小。
     * 通过设置inSampleSize可以修改显示该图片需要的内存大小。比如原来需要20M
     * ,那么如果inSampleSize=5,则实际显示的时候只需要5M就够了。 
     */
    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) {

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

    /**
     * 
     * @param res 使用getResources()即可
     * @param resId 图片的id
     * @param reqWidth 要求的高度
     * @param reqHeight 要求的宽度
     * @return 将会返回一个已经根据要求的高度和宽度缩放的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();
        /*
         * 如果我们把它设为true,那么BitmapFactory.decodeFile(String path, Options
         * opt)并不会真的返回一个Bitmap给你,它仅仅会把它的宽,高取回来给你,这样就不会占用太多的内存,也就不会那么频繁的发生OOM了。
         */
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(res, resId, options);

        // Calculate inSampleSize
        options.inSampleSize = calculateInSampleSize(options, reqWidth,
                reqHeight);
        // Decode bitmap with inSampleSize set

        // 把inJustDecodeBounds设置为false,这样通过BitmapFactory生成bitmap时就会返回一个真的bitmap而不是null;
        options.inJustDecodeBounds = false;
        //根据图片的来源确定到底使用哪一种生成BitmapFactory的方法。
        return BitmapFactory.decodeResource(res, resId, options);
    }

}

MainActivity

package com.example.loadbigbitmap;

import android.app.Activity;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.widget.ImageView;

public class MainActivity extends Activity {
    /*
     * 显示图片
     */
    private ImageView image;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        intiUI();
        /*
         * 图片的原始宽度,高度,类型: 1024;768;image/jpeg
         */

        Bitmap bitmap = ImageUtil.decodeSampledBitmapFromResource(getResources(), R.drawable.default_bg, 100, 100);
        image.setImageBitmap(bitmap);

    }

    private void intiUI() {
        image = (ImageView) findViewById(R.id.image);

    }
}
接下来我就会一步一步的从bitmap的生成到BitmapFactory.Options类的
对象的属性的设置。来讲解如何缩放大容量Bitmap。
BitmapFactory有很多方式生成Bitmap。(decodeByteArray(), decodeFile(), decodeResource(), etc.)
 这里我们使用decodeResource()方法生成bitmap,其他方法大同小异,可以根据自己的需求修改。
    BitmapFactory.decodeResource(getResources(),R.drawable.default_bg, options);

第一个参数是Resources,直接getResources()就行了,第二个参数是图片的id,第三个参数就是BitmapFactory.Options了,它通过:

final BitmapFactory.Options options = new BitmapFactory.Options();

来获取。

通过options.inSampleSize的设置控制显示图片所需要的大小
整篇文章所需要做的就是设置这个值,假设inSampleSize=5.则根据这个options作为参数,加载的图片的内存就会是原来的1/5。

我们应该根据图片原有的高度,宽度,与需要显示的高度宽度的比例来计算出这个inSampleSize的大小,如何计算请参考代码ImageUtil类里的calculateInSampleSize方法。
假设需要显示的高度和宽度已经知道了,如何取得图片原有的高度和宽度呢?
这时候我们就需要先设置options.inJustDecodeBounds = true;设置成true后再执行BitmapFactory.decodeResource(res, resId, options);方法则安卓系统并不会真的去解码生成一个bitmap,而是返回一个NULL,但是这执行完后的options就会拥有图片的高度,宽度,类型等属性了。
有了这个属性,再执行

options.inSampleSize = calculateInSampleSize(options, reqWidth,
                reqHeight);

就对inSampleSize 的值设置成功了。
这时候再执行

        // 把inJustDecodeBounds设置为false,这样通过BitmapFactory生成bitmap时就会返回一个真的bitmap而不是null;
        options.inJustDecodeBounds = false;
        //根据图片的来源确定到底使用哪一种生成BitmapFactory的方法。
        return BitmapFactory.decodeResource(res, resId, options);

便能得到一个缩小之后的bitmap。且不会再占用很大的内存。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值