ImageLoader

概要:

ImageLoader,图片加载类。在Android中经常使用到图片加载。所以一个好的图片的加载类

对一个优秀的app非常重要。本文中是一个自定义的ImageLoader,是主要涉及两个方面:

一,图片的高效加载,主要通过BitmapFactory.Options来缩放图片。我们需要加载的图片如果

大于我们展示图片的控件大小,就会造成内存的浪费。这时我们可以通过Options.inSampleSize来

设置图片缩小的倍数。

二,图片的缓存策越,如果每次都从需要的图片都从网络中获取,会浪费用户的流量,而且不高效。

这里使用LruCache实现内存缓存。DiskLruCache实现磁盘缓存。


分析:

一,图片的高效的加载。

我们在使用BitmapFactory加载图片是,会直接或间接的使用Option。通过设定Option.inSampleSize

来控制加载图片的大小。在Android官方文档中,inSampleSize推荐为2的指数,例如有一张1024*1024*4

(4MB)的图片,当inSampleSize=2时,加载后的Bitmap为512*512*4(1MB),所占内存为原来的1/4。

二,图片的缓存策越,我们加载图片的策越:

1,读取内存缓存,先从内存缓存(MemoryLRUCache)中,查找所需图片。不为null则返回。为null则

执行下一步。

2,读取本地缓存,从磁盘缓存(DiskLRUCache)中,查找所需图片,不为nulll则返回,并将Bitmap添加

到内存缓存(MemoryLRUCache),为nul则执行下一步。

3,读取网络资源,从网络中下载图片到本地即磁盘缓存,然后读取本地缓存。


应用:

一,高效加载图片。

1,从resource中加载图片。

    public Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) {
        final BitmapFactory.Options options = new BitmapFactory.Options();
        // 第一次加载只获取图片的信息
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(res, resId, options);
        // 计算inSampleSize
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
        // 正式加载Bitmap
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeResource(res, resId, options);
    }

2,从文件流中加载图片。

    /**
     * 不能直接对文件流做如下操作,因为两次的decodeStream会影响文件的位置属性
     * 导致第二次decodeStream的返回为null,所以中转一下
     * FileDescriptor fileDescriptor = FileInputStream.getFD();
     */
    public Bitmap decodeSampledBitmapFromFileDescriptor(FileDescriptor descriptor, int reqWidth, int reqHeight) {
        final BitmapFactory.Options options = new BitmapFactory.Options();
        //从文件信息中提取高宽信息
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFileDescriptor(descriptor, null, options);
        //计算inSampleSize
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
        //正式加载Bitmap
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeFileDescriptor(descriptor, null, options);
    }

3,计算inSampleSize。

    public int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
        if (reqWidth == 0 || reqHeight == 0) {
            return 1;
        }
        final int width = options.outWidth;
        final int height = options.outHeight;
        Log.i(tag, "outOption: height:" + height + ",widht:" + width);
        int inSampleSize = 1;
        if (width > reqWidth && height > reqHeight) {
            int halfWith = options.outWidth / 2;
            int halfHeight = options.outHeight / 2;

            while (halfWith / inSampleSize >= reqWidth && halfHeight / inSampleSize >= reqHeight) {
                inSampleSize *= 2;
            }
        }
        Log.i(tag, "sampleSize:" + inSampleSize);
        return inSampleSize;
    }

二,图片的缓存策越

1,读取内存缓存

    private Bitmap loadBitmapFromMemoryCache(String url) {
        String key = hashKeyFromUrl(url);//有个加密算法
        return getBitmapFromMemoryCache(key);
    }
2,读取本地缓存

    /**
     * 从磁盘中读取Bitmap,并将其添加到内存缓存
     *
     */
    private Bitmap loadBitmapFromDiskLruCache(String url, int reqWidth, int reqHeight)
            throws IOException {
        Log.w(tag, "loadBitmapFromDiskLruCache");
        if (Looper.myLooper() == Looper.getMainLooper()) {
            Log.w(tag, "load bitmap from ui thread, it is not recommended");
        }
        if (mDiskLruCache == null) {
            return null;
        }

        Bitmap bitmap = null;
        String key = hashKeyFromUrl(url);

        DiskLruCache.Snapshot snapshot = mDiskLruCache.get(key);
        if (snapshot != null) {
            FileInputStream inputStream = (FileInputStream) snapshot.getInputStream(DISK_CACHE_INDEX);
            FileDescriptor descriptor = inputStream.getFD();
            bitmap = mImageResizer.decodeSampledBitmapFromFileDescriptor(descriptor, reqWidth, reqHeight);
            if (bitmap != null) {
                addBitmapToMemoryCache(key, bitmap);
            }
        }
        return bitmap;
    }

3,读取网络资源

    /**
     * 读取网络资源并将它写入磁盘缓存
     */
    private Bitmap loadBitmapFromHttp(String url, int reqWidth, int reqHeight) throws IOException {
        if (Looper.myLooper() == Looper.getMainLooper()) {
            throw new RuntimeException("can not visit network from ui thread");
        }
        if (mDiskLruCache == null) {
            return null;
        }
        String key = hashKeyFromUrl(url);
        DiskLruCache.Editor editor = mDiskLruCache.edit(key);
        if (editor != null) {
            OutputStream outputStream = editor.newOutputStream(DISK_CACHE_INDEX);
            if (downloadUrlToStream(url, outputStream)) {
                editor.commit();
            } else {
                editor.abort();
            }
            mDiskLruCache.flush();
        }
        return loadBitmapFromDiskLruCache(url, reqWidth, reqHeight);
    }


验证demo





评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值