Bitmap-让图片加载更高效

0. 效果图

这里写图片描述

1. 基本概念

  • Bitmap(位图)是Android系统中图像处理最重要的类之一。
  • Bitmap能够获取到图片的信息:高和宽的像素值以及总的像素值、alpha像素值等。
  • Bitmap获取到图片信息后,能够对其进行裁剪、缩放等操做。
  • Bitmap能够经过一个Bitmap建立新的Bitmap。程序员

  • 总之:Bitmap为咱们程序员提供了对图像文件的操做支持。(就像File类为咱们提供了对本地本件的操做支持同样)web

2. 高效加载应用场景

  • 假设经过ImageView来显示图片,可是不少时候ImageView并无图片的原始尺寸那么大,这个时候把整个图片加载进来后再设给ImageIiew根本没有必要,由于ImageView没有办法显示原始的图片。
  • 经过BitmapFactory.Options就能够按必定的采样率来加载缩小后的图片,将缩小后的图片在ImageView中显示,这样就会下降内存占用从而在必定程度上避免OOM,提升了Btimap加载时的性能。
  • BitmapFactory提供的加载图片的四类方法都支持BitmapFactory.Options参数,经过四类加载方式能够很方便的对一个图片进行采样缩放。

3. 高效加载的核心思想

  • 采用BitmapFactory.Options来加载所需尺寸的图片。

4. 四种Bitmap的加载方式

  • decodeFile:从文件系统中加载
  • decodeResource: 从资源中加载
  • decodeStream:从输入中流加载
  • decodeByteArray:从字节数组中加载

5. 具体分析高效加载

  • 经过BitmapFactory.Options来缩放图片,主要是用到了它的inSampleSize参数,即采样率。
  • 当inSampleSize为1时,采样后的图片大小为图片的原始大小;当inSampleSize大于1时,好比为2,那么采样后的图片其宽/高均为原图大小的1/2,而像素数为原图的1/4,其占有的内存大小也为原图的1/4.
  • 拿一张1024 x 1024像素的图片来讲,假定采用ARG8888格式存储,那么占有的内存为1024 x 1024 x 4,即4M(ARG8888 表明每一个像素占8个字节,也就是1个byte,1024个byte等于1kb,1024kb是1M),若是inSampleSize为2,那么采样后的图片其内存占有只有512 x 512 x 4,即1MB.
  • 能够发现采样率inSampleSize必须是大于1的整数,图片才会有缩小的效果,而且采样率同时做用于宽/高,这将致使缩放后的图片以采样率的2次方形式递减,即缩放比例为1/(inSampleSize 的2次方),好比inSampleSize为4,那么缩放比例就是1/16.
  • 有一种特殊的状况:inSampleSize小于1时,其做用至关于1,即无缩放效果。

6. 采样率的开发建议

  • inSampleSize的取值应该老是2的指数,好比一、二、四、八、16,等等。若是外界传递给系统的inSampleSize不为2的指数,那么系统会向下取整并选择一个最接近的2的指数来代替,好比3,系统会选择2来代替,固然因为国内手机的私人订制,并不是全部Android版本上都成立,所以把它看成一个开发建议便可。

7. 获取采样率的步骤

步骤:数组

  1. 将BitmapFactory.Options的inJustDecodeBounds参数设为true并加载图片。
  2. 从BitmapFactory.Options中取出图片的原始宽高信息,它们对应于outWidth和outHeight参数。
  3. 根据采样率的规则并结合目标View的所需大小计算出采样率inSampleSize
  4. 将BitmapFactory.Options的inJustDecodeBounds参数设为false,而后从新加载图片。

注意: svg

  • InJustDecodeBounds参数,当此参数设置为true时,Bitmap只会解析图片的原始宽/高信息,并不会去真正地加载图片。
  • 这个时候BitmapFactory获取的图片宽和高的信息和图片的位置以及程序运行的设备有关,好比同一张图片放在不一样的drawable目录下或者运行在不一样屏幕密度的设备上,均可能致使BitmapFactory获取到不一样的结果。

8. 代码实现

public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(res, resId, options);

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

        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeResource(res, resId, options);
    }

    private static int calulateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
        if (reqWidth == 0 || reqHeight == 0) {
            return 1;
        }
        int outHeight = options.outHeight;
        int outWidth = options.outWidth;
        int inSampleSize = 1;

        if (outHeight > reqHeight || outWidth > reqWidth) {
            int halfHeight = outHeight / 2;
            int halfWidth = outWidth / 2;
            while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) {
                inSampleSize *= 2;
            }
        }
        return inSampleSize;
    }
Bitmap bitmap = decodeSampledBitmapFromResource(getResources(), R.drawable.testbitmap, 300, 300);
                imageView.setImageBitmap(bitmap);

说明:建立drawable-xxxhdpi文件夹,文件夹下放一张3840*2160的图片,而后咱们用bitmap来加载为300x300的图片。如文章开头图片。性能