【 Android 】高效加载 Bitmap

作者: Tyhoo_Wu | 来源:发表于2018-05-13 11:56 被阅读206次

Bitmap是 Android 系统中图像处理的最重要的类之一。通过Bitmap我们可以获取到图片的信息(宽度的像素值,高度的像素值,总的像素值,α 值,还可以通过Bitmap去创建一个新的Bitmap等)。获取到信息之后,可以对其进行缩放、裁剪等操作。

Bitmap 加载方式

BitmapFactory.decodeByteArray()      // 将 字节数组 decode 成 Bitmap
BitmapFactory.decodeFile()           // 将 文件 decode 成 Bitmap
BitmapFactory.decodeResource()       // 将 资源 decode 成 Bitmap
BitmapFactory.decodeStream()         // 将 流 decode 成 Bitmap

示例:

Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher, null);

Q: 为什么是Bitmap bitmap = BitmapFactory.decodeXxx而不是Bitmap bitmap = new Bitmap()?
A: 因为Bitmap可能会非常的占用内存,所以系统帮我们创建了一个工厂类来decode不同的Bitmap,而且Bitmap本生方法是私有的,不允许我们直接 new 一个Bitmap

高效加载

图片是一个对内存消耗很大的事物,目前主流手机的像素都是千万像素的,一张照片就会达到几兆~几十兆,我们不应该把这么大的一个事物直接加载到内存里,容易导致 OOM(内存溢出),所以我们应该尽可能的节省内存开销,使应用运行的更加流畅。

关键字:BitmapFactory.Options

官方API文档:https://developer.android.google.cn/reference/android/graphics/BitmapFactory.Options

BitmapFactory.Options 有如下几个重要的属性:

说明:inJustDecodeBoundsboolean型变量,如果把它设置为true,在BitmapFactory.decodeXxx的时候并不会真正的返回一个Bitmap而是返回Bitmapwidthheight,而且把这个widthheight传到outWidthoutHeight这两个字段中。inSampleSize是采样率,通过这个采样率我们可以极大的减少图片内存占用。

示例(对图片进行压缩,并打印出压缩前后图片占用内存大小):

1. 自定义压缩图片方法

/**
 * 
 *
 * @param filePath 图片路径
 * @param width    要显示的图片宽度
 * @param height   要显示的图片高度
 * @return 压缩后图片
 */
private Bitmap ratioBitmap(String filePath, int width, int height) {
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;  // 目的:只加载图片的宽和高,而不加载图片的真正内容
    options.inPreferredConfig = Bitmap.Config.ARGB_8888;  // 设置图片解码时使用的颜色模式

    // 预加载
    BitmapFactory.decodeFile(filePath, options);

    // 获取图片宽高
    int originalWidth = options.outWidth;
    int originalHeight = options.outHeight;

    // 加载图片的真正内容
    options.inJustDecodeBounds = false;

    // 对图片进行采样
    options.inSampleSize = getSampleSize(originalWidth, originalHeight, width, height);

    return BitmapFactory.decodeFile(filePath, options);
}

2. 自定义获取采样率方法

/**
 * 获取采样率
 *
 * @param originalWidth  原始图片宽度
 * @param originalHeight 原始图片高度
 * @param width          要显示的图片宽度
 * @param height         要显示的图片高度
 * @return 采样率
 */
private int getSampleSize(int originalWidth, int originalHeight, int width, int height) {
    // 初始化采样率
    int sampleSize = 1;

    if (originalWidth > originalHeight && originalWidth > width) {
        // 用宽度计算采样率
        sampleSize = originalWidth / width;
    } else if (originalWidth < originalHeight && originalHeight > height) {

        Log.d(TAG, "originalHeight: " + originalHeight);
        Log.d(TAG, "height: " + height);

        // 用高度计算采样率
        sampleSize = originalHeight / height;
    }

    if (sampleSize <= 0) {
        sampleSize = 1;
    }

    return sampleSize;
}

3. 对本地图片进行压缩

图片路径

String filePath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "demo.png";
未压缩的图片

Bitmap bitmap = BitmapFactory.decodeFile(filePath);
Log.d(TAG, "未压缩的图片: " + bitmap.getByteCount());
压缩后的图片

bitmap = ratioBitmap(filePath, mIv.getWidth(), mIv.getHeight());
Log.d(TAG, "压缩后的图片: " + bitmap.getByteCount());

(注: mIv 就是一个简单的 ImageView,宽高随意设置,这里布局文件就不贴出来了)
Log 日志

未压缩的图片: 3686400
压缩后的图片: 921600

通过对比可以看到,压缩的大小还是很明显的。

相关文章

网友评论

  • AlanFu:“options.inPreferredConfig = Bitmap.Config.ARGB_8888; // 设置图片解码时使用的颜色模式“ (ARGB_8888= Each pixel is stored on 4 bytes. )可以改成”RGB_565“ ”(Each pixel is stored on 2 bytes and only the RGB channels are encoded: red is stored with 5 bits of precision (32 possible values), green is stored with 6 bits of precision (64 possible values) and blue is stored with 5 bits of precision. “)
    Tyhoo_Wu:@Code27149 嗯,只是个 Sample,选择什么颜色模式 还要看实际使用的场景。ALPHA_8、RGB_565、ARGB_4444(不推荐)、ARGB_8888 等
    AlanFu:这样可以大大减小占用的内存。

本文标题:【 Android 】高效加载 Bitmap

本文链接:https://www.haomeiwen.com/subject/tavkdftx.html