美文网首页
Bitmap-让图片加载更高效

Bitmap-让图片加载更高效

作者: 付凯强 | 来源:发表于2018-03-04 14:35 被阅读0次

    0. 效果图

    1. 基本概念

    • Bitmap(位图)是Android系统中图像处理最重要的类之一。

    • Bitmap可以获取到图片的信息:高和宽的像素值以及总的像素值、alpha像素值等。

    • Bitmap获取到图片信息后,可以对其进行裁剪、缩放等操作。

    • Bitmap可以通过一个Bitmap创建新的Bitmap。

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

    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的指数,比如1、2、4、8、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,然后重新加载图片。

    注意:

    • 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;
            options.inPreferredConfig = Bitmap.Config.RGB_565;
            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的图片。如文章开头图片。

    相关文章

      网友评论

          本文标题:Bitmap-让图片加载更高效

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