Android 图片如何高效加载与缓存 (4.5) —— 缩略图生成的优化

来源:互联网 发布:淘宝如何代运营 编辑:程序博客网 时间:2024/05/16 18:04

在之前那篇里面仍有不足之处,比如:

一张4000*3000的图片压缩到了300*200的大小,然后输出到ImageView上。但是ImageView的大小可能只有100*100,这样我们仍然占用了很多不需要的内存。所以我们只需要将图片居中裁剪成ImageView的大小即可。

知道了如何做之后,在考虑一下可能存在的图片尺寸与ImageView尺寸之间的关系:

1.图片的宽 小于 ImageView的宽 (比如:5000*10)
2.图片的高 小于 ImageView的高 (比如:10*5000)
3.图片的宽和高都 小于 ImageView的宽高 (比如:1*1)

考虑好了之后,我们就能动手写代码了!

先来个大合照,然后我在把裁剪的方法一一拿出来说吧 = n =

    /*    获取图片缩略图任务     */    private class GenerateImageThumbnail implements Callable<String>{        private int scaleTimes;  //缩放倍数        private String path;  //图片路径        private String tag;  //图片加载任务唯一TAG        private ImageView imageView;  //图片接收的ImageView        private Bitmap bitmap;  //图片的Bitmap对象        private HandleOnLoaded handleOnLoaded;  //图片效果处理回调        public GenerateImageThumbnail(String path, String tag, ImageView imageView, HandleOnLoaded handleOnLoaded) {            this.path = path;            this.tag = tag;            this.imageView = imageView;            this.handleOnLoaded = handleOnLoaded;        }        @Override        public String call() throws Exception {            try {                //进行图片剪裁                bitmap = cropBitmap();            } catch (IllegalArgumentException e) {                //如果裁剪出现了异常                fetherExecutor.removeTag(tag);                Log.d("OCImageLoader", "Exception on croping bitmap. "+e);                runOnUIThread(new Runnable() {                    @Override                    public void run() {                        onError();                    }                });                return null;            }            if (handleOnLoaded != null){                //如果有需要进行图片处理,则使用回调处理                bitmap = handleOnLoaded.reduce(bitmap,tag);            }            if (bitmap != null){                //图片进行缓存                imageCacher.putCache(tag,bitmap);                runOnUIThread(new Runnable() {                    @Override                    public void run() {                        onCompleted(imageView , bitmap);                    }                });            }            fetherExecutor.removeTag(tag);            return null;        }        //加载完成的操作        private void onCompleted(ImageView imageView , Bitmap bitmap){            ...        }        //加载失败的操作        private void onError(){            ...        }        /**         * 进行 Bitmap 的裁剪缩放操作         * @return  处理后的Bitmap         */        private Bitmap cropBitmap() throws IllegalArgumentException{            ...        }        /**         * 普通裁剪         * @return  裁剪后的Bitmap         */        private Bitmap normalCropBitmap(int pictureWidth , int pictureHeight , int showHeight , int showWidth , BitmapFactory.Options options)        throws IllegalArgumentException{            ...        }        /**         * 高度裁剪         * @return  裁剪后的Bitmap         */        private Bitmap heightCropBitmap(int pictureWidth , int pictureHeight , int showHeight , BitmapFactory.Options options)        throws IllegalArgumentException{            ...        }        /**         * 长度裁剪         * @return  裁剪后的Bitmap         */        private Bitmap widthCropBitmap(int pictureWidth , int pictureHeight , int showWidth , BitmapFactory.Options options)        throws IllegalArgumentException{            ...        }    }

方法 cropBitmap() 用于初始化数据 以及判断应该如何裁剪

private Bitmap cropBitmap() throws IllegalArgumentException{            //默认起始缩放倍数            scaleTimes = 2;            //先仅仅加载图片的尺寸数据            BitmapFactory.Options options = new BitmapFactory.Options();            options.inJustDecodeBounds = true;            BitmapFactory.decodeFile(path,options);            //裁剪方式            int cropType;            //原图尺寸            int pictureWidth = options.outWidth;            int pictureHeight = options.outHeight;            //ImageView尺寸. 先尽可能缩放成这个尺寸            int showWidth = imageView.getMeasuredWidth();            int showHeight = imageView.getMeasuredHeight();            if (showHeight * showWidth == 0){                //如果有一项ImageView尺寸的数据为 0 , 则赋予默认值. 裁剪为普通状态                showHeight = 120;                showWidth = 120;                cropType = 0;            }else if ( pictureHeight < showHeight && pictureWidth < showWidth ){                //如果原图小于要显示的尺寸,则直接返回原图对象                return BitmapFactory.decodeFile(path);            }else if ( pictureHeight < showHeight ){                //如果原图的高度小于要显示的尺寸,就直接将  原图的长度  进行裁剪                cropType = 1;            }else if ( pictureWidth < showWidth ){                //如果原图的宽度小于要显示的尺寸,就直接将  原图的高度  进行裁剪                cropType = 2;            }else {                //普通状态                cropType = 0;            }            switch (cropType){                case 0:                    //普通裁剪                    bitmap = normalCropBitmap(pictureWidth,pictureHeight,showHeight,showWidth,options);                    break;                case 1:                    //长度裁剪                    bitmap = widthCropBitmap(pictureWidth,pictureHeight,showWidth,options);                    break;                case 2:                    //高度裁剪                    bitmap = heightCropBitmap(pictureWidth,pictureHeight,showHeight,options);                    break;                default:                    bitmap = normalCropBitmap(pictureWidth,pictureHeight,showHeight,showWidth,options);                    break;            }            return bitmap;        }

方法 normalCropBitmap() 默认裁剪方式

/**         * 普通裁剪         * @return  裁剪后的Bitmap         */        private Bitmap normalCropBitmap(int pictureWidth , int pictureHeight , int showHeight , int showWidth , BitmapFactory.Options options)        throws IllegalArgumentException{            //临时存储计算得到的上一次结果,预设为图片原始尺寸.            int reducedWidth = pictureWidth;            int reducedHeight = pictureHeight;            int lastWidth;            int lastHeight;            while (true){                lastWidth = pictureWidth/scaleTimes;                lastHeight = pictureHeight/scaleTimes;                if ( lastHeight < showHeight || lastWidth < showWidth){                    //如果计算得到的尺寸小于要得到的尺寸,则跳出                    break;                }else {                    //否则就继续增大缩放倍数,同时记录这次的尺寸                    reducedWidth = lastWidth;                    reducedHeight = lastHeight;                    scaleTimes += 1;                }            }            //用得出的尺寸数据,计算出缩放倍数,然后读取图片            options.inJustDecodeBounds = false;            options.inPreferredConfig = Bitmap.Config.RGB_565;            options.inSampleSize = (pictureHeight / reducedHeight + pictureWidth / reducedWidth) /2;            //获取等待截取的Bitmap            Bitmap pictureBitmap = BitmapFactory.decodeFile(path,options);            //计算裁剪的起点            int cropX , cropY;            cropX = (reducedWidth/2)-(showWidth/2);            cropY = (reducedHeight/2)-(showHeight/2);            //剪!            pictureBitmap = Bitmap.createBitmap(pictureBitmap,cropX,cropY,showWidth,showHeight);            return pictureBitmap;        }

方法 heightCropBitmap() 高度的裁剪

        /**         * 高度裁剪         * @return  裁剪后的Bitmap         */        private Bitmap heightCropBitmap(int pictureWidth , int pictureHeight , int showHeight , BitmapFactory.Options options)        throws IllegalArgumentException{            //图片不用缩放了,计算下裁剪的居中位置,就能直接裁剪了.下一个方法也一样.            int cropY = ( pictureHeight / 2 ) - ( showHeight / 2 );            options.inJustDecodeBounds = false;            options.inPreferredConfig = Bitmap.Config.RGB_565;            bitmap = BitmapFactory.decodeFile(path,options);            bitmap = Bitmap.createBitmap(bitmap,0,cropY,pictureWidth,showHeight);            return bitmap;        }

方法 widthCropBitmap() 宽度的裁剪

        /**         * 宽度裁剪         * @return  裁剪后的Bitmap         */        private Bitmap widthCropBitmap(int pictureWidth , int pictureHeight , int showWidth , BitmapFactory.Options options)        throws IllegalArgumentException{            int cropX = ( pictureWidth / 2 ) - ( showWidth / 2 );            options.inJustDecodeBounds = false;            options.inPreferredConfig = Bitmap.Config.RGB_565;            bitmap = BitmapFactory.decodeFile(path,options);            bitmap = Bitmap.createBitmap(bitmap,cropX,0,showWidth,pictureHeight);            return bitmap;        }

下面是正常向的图片处理之后的Log 可以看到无论图片尺寸是如何的,处理后的大小都是统一的
这里写图片描述

下面这是特殊情况的log
这里写图片描述

0 0