Mark Xu 的博客

记录精彩的程序人生

Android 图片加载(二)-- Bitmap 高效加载

上一章中,我们介绍了图片的基本知识,接下来我们看看在 Android 中如何高效加载图片呢。

在 Android 中,我们使用 Bitmap 对象来描述我们前面所说的图片,Bitmap 本身的含义为:位图,我们用它来处理图片。那么 Bitmap 对象要如何得到呢?

Bitmap 对象

Android 系统 API 中提供了一个工厂类 BitmapFactory,用于从文件系统、资源、输入流以及字节数组中加载出一个 Bitmap 对象。

public static Bitmap decodeFile(String pathName) {}

public static Bitmap decodeResource(Resources res, int id) {}

public static Bitmap decodeByteArray(byte[] data, int offset, int length) {}

public static Bitmap decodeStream(InputStream is) {}

其中 decodeFile 方法和 decodeResource 方法最终调用了 decodeStream 方法,decodeStream、decodeByteArray 方法最终调用了几个 native 方法。

Bitmap 二次采样

public static Bitmap decodeFile(String pathName) {
    return decodeFile(pathName, null);
}

在上面几个方法中,可以看到都调用了相应的重载方法,第二个参数为 null,代表什么呢,原来第二个参数为 Options,BitmapFactory 的一个静态内部类,里面存储了一些加载 Bitmap 时需要用到的信息。

当我们在应用中需要将一张分辨率为 1600*1200 的图片显示出来,目标 ImageView 的大小为 400*300,在这种情况下,我们就无需把整张图片加载到内存中,然后再显示到 ImageView 上。可以通过配置参数 Options ,进行按需加载。

下面的代码片段节选自 https://blog.csdn.net/u012702547/article/details/51245133

public static Bitmap getBitmap(String filePath, int destWidth, int destHeight) {
    BitmapFactory.Options options = new BitmapFactory.Options();
    // inJustDecodeBounds 属性设置为 true 时,decode... 方法返回 null,但是所有的 out 开头的属性依然会设置,方便我们在不加载图片到内存中的情况下获取图片的一些信息
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(filePath, options);
    // 拿到原图的宽高
    int outWidth = options.outWidth;
    int outHeight = options.outHeight;
    // 定义缩放比例
    int sampleSize = 1;
    // 如果宽高的任意一方的缩放比例没有达到要求,都继续增大缩放比例
    while (outWidth / sampleSize > destWidth || outHeight / sampleSize > destHeight) {
        sampleSize *= 2;
    }

    options.inJustDecodeBounds = false;
    options.inSampleSize = sampleSize;
    options.inPreferredConfig = Bitmap.Config.ARGB_8888;
    return BitmapFactory.decodeFile(filePath, options);
}

可以看到,按需加载需要进行两次采样:

  • 第一次采样:根据原始图片宽高和目标 View 的宽高,获取合适的压缩比例
  • 第二次采样:按压缩比例进行图片加载
留下你的脚步