UniversalImageLoader基础

一、简介

UniversalImageLoader是一个开源图片加载库,内部使用了内存缓存、本地缓存、网络下载实现了加载bitmap的功能;内存缓存有LruMemoryCache(默认)等缓存策略。

二、基础用法

// 1.设置加载图片的选项
DisplayImageOptions displayImageOptions = new DisplayImageOptions.Builder()
        .cacheInMemory(true)
        .cacheOnDisk(false)
        .bitmapConfig(Bitmap.Config.ARGB_8888)
        .imageScaleType(ImageScaleType.EXACTLY_STRETCHED)
        .considerExifParams(true)
        .build();
// 2.加载图片
ImageLoader.getInstance().loadImage(netUrl, displayImageOptions,
        new ImageLoadingListener() {
        @Override
        public void onLoadingStarted(String imageUri, View view) { }

		@Override
		public void onLoadingFailed(String imageUri, View view, FailReason failReason) { }

		@Override
		public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) { }

		@Override
		public void onLoadingCancelled(String imageUri, View view) { }
        });

三、源码分析

源码从ImageLoader.getInstance().loadImage()开始分析:

public class ImageLoader {
	// 调用入口
	public void loadImage(String uri, ImageSize targetImageSize, DisplayImageOptions options,
                          ImageLoadingListener listener, ImageLoadingProgressListener progressListener) {
        checkConfiguration();
        if (targetImageSize == null) {
            targetImageSize = configuration.getMaxImageSize();
        }
        if (options == null) {
            options = configuration.defaultDisplayImageOptions;
        }

        NonViewAware imageAware = new NonViewAware(uri, targetImageSize, ViewScaleType.CROP);
        displayImage(uri, imageAware, options, listener, progressListener);
    }
    
    // 加载图片
    public void displayImage(String uri, ImageAware imageAware, DisplayImageOptions options,
                             ImageLoadingListener listener, ImageLoadingProgressListener progressListener) {
        // 1.内存缓存中是否存在,默认为LruMemoryCache
        Bitmap bmp = configuration.memoryCache.get(memoryCacheKey);
        if (bmp != null && !bmp.isRecycled()) {
            // ...省略部分代码
            listener.onLoadingComplete(uri, imageAware.getWrappedView(), bmp);
        } else {
            ImageLoadingInfo imageLoadingInfo = new ImageLoadingInfo(uri, imageAware, targetSize, memoryCacheKey,
                    options, listener, progressListener, engine.getLockForUri(uri));
            // 封装成LoadAndDisplayImageTask从本地缓存查找/发送网络请求
            LoadAndDisplayImageTask displayTask = new LoadAndDisplayImageTask(engine, imageLoadingInfo,
                    defineHandler(options));
            if (options.isSyncLoading()) {
                displayTask.run();
            } else {
                engine.submit(displayTask);
            }
        }
    }
}

四、内存缓存

内存缓存LruMemoryCache是通过LinkedHashMap实现了最近最少使用算法。

public class LruMemoryCache implements MemoryCache {

    private final LinkedHashMap<String, Bitmap> map;
    
    public LruMemoryCache(int maxSize) {
        if (maxSize <= 0) {
            throw new IllegalArgumentException("maxSize <= 0");
        }
        this.maxSize = maxSize;
        this.map = new LinkedHashMap<String, Bitmap>(0, 0.75f, true);
    }
    @Override
    public final Bitmap get(String key) {
        if (key == null) {
            throw new NullPointerException("key == null");
        }

        synchronized(this) {
            return map.get(key);
        }
    }

    /**
     * Caches {@code Bitmap} for {@code key}. The Bitmap is moved to the head of the queue.
     */
    @Override
    public final boolean put(String key, Bitmap value) {
        if (key == null || value == null) {
            throw new NullPointerException("key == null || value == null");
        }

        synchronized(this) {
            size += sizeOf(key, value);
            Bitmap previous = map.put(key, value);
            if (previous != null) {
                size -= sizeOf(key, previous);
            }
        }

        trimToSize(maxSize);
        return true;
    }
    @Override
    public final Bitmap remove(String key) {
        if (key == null) {
            throw new NullPointerException("key == null");
        }

        synchronized(this) {
            Bitmap previous = map.remove(key);
            if (previous != null) {
                size -= sizeOf(key, previous);
            }
            return previous;
        }
    }
}

五、LinkedHashMap实现LRU

LRU是最近最少使用算法,实现的算法有多种,比如对每个数据都新增一个时间戳字段等;考虑到算法执行效率,一般采用链表+HashMap的实现方式。

LinkedHashMap内部实现LRU是通过HashMap+双链表方式实现的,当需要插入新的数据项的时候,如果新数据项在链表中存在(一般称为命中),则把该节点移到链表尾部,如果不存在,则新建一个节点,放到链表尾部。在访问数据的时候,如果数据项在链表中存在,则把该节点移到链表尾部,否则返回-1。这样,尾节点存放最近被访问的数据项,头节点存放最久未访问的数据项,若缓存满了,则删除头节点即可。

public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V> {
	// 头节点,最久未访问的数据 eldest
	transient LinkedHashMapEntry<K,V> head;
	// 尾节点,最近被访问的数据 youngest
    transient LinkedHashMapEntry<K,V> tail;
    
    // 获取某个节点
    public V get(Object key) {
        Node<K,V> e;
        if ((e = getNode(hash(key), key)) == null)
            return null;
        if (accessOrder)
        	// 在节点被访问后,更新头节点、尾节点
            afterNodeAccess(e);
        return e.value;
    }
    
    // 在节点被访问后,更新头节点、尾节点
    void afterNodeAccess(Node<K,V> e) { // move node to last
        LinkedHashMapEntry<K,V> last;
        if (accessOrder && (last = tail) != e) {
            LinkedHashMapEntry<K,V> p =
                (LinkedHashMapEntry<K,V>)e, b = p.before, a = p.after;
            p.after = null;
            if (b == null)
                head = a;
            else
                b.after = a;
            if (a != null)
                a.before = b;
            else
                last = b;
            if (last == null)
                head = p;
            else {
                p.before = last;
                last.after = p;
            }
            tail = p;
            ++modCount;
        }
    }
}

The End

欢迎关注我,一起解锁更多技能:BC的掘金主页~💐 BC的CSDN主页~💐💐
请添加图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值