ImageLoader内存缓存解析

来源:互联网 发布:python和大数据挖掘 编辑:程序博客网 时间:2024/06/05 18:35

接下来我要说的就是鼎鼎大名的Universal Image Loader,上一篇讲了ImageLoader硬盘缓存解析,本篇将介绍ImageLoader的内存缓存。


先来看看ImageLoader内存缓存部分的代码结构。



首先是MemoryCache接口


public interface MemoryCache {/** * Puts value into cache by key * * @return <b>true</b> - if value was put into cache successfully, <b>false</b> - if value was <b>not</b> put into * cache */boolean put(String key, Bitmap value);/** Returns value by key. If there is no value for key then null will be returned. */Bitmap get(String key);/** Removes item by key */Bitmap remove(String key);/** Returns all keys of cache */Collection<String> keys();/** Remove all items from cache */void clear();}

接口很简单,就是5个方法,对内存缓存进行处理。


接下来是BaseMemoryCache,在实现MemoryCache接口的同时做了下拓展。


/******************************************************************************* * Copyright 2011-2014 Sergey Tarasevich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/package com.nostra13.universalimageloader.cache.memory;import android.graphics.Bitmap;import java.lang.ref.Reference;import java.util.*;/** * Base memory cache. Implements common functionality for memory cache. Provides object references ( * {@linkplain Reference not strong}) storing. * * @author Sergey Tarasevich (nostra13[at]gmail[dot]com) * @since 1.0.0 */public abstract class BaseMemoryCache implements MemoryCache {/** Stores not strong references to objects */private final Map<String, Reference<Bitmap>> softMap = Collections.synchronizedMap(new HashMap<String, Reference<Bitmap>>());@Overridepublic Bitmap get(String key) {Bitmap result = null;Reference<Bitmap> reference = softMap.get(key);if (reference != null) {result = reference.get();}return result;}@Overridepublic boolean put(String key, Bitmap value) {softMap.put(key, createReference(value));return true;}@Overridepublic Bitmap remove(String key) {Reference<Bitmap> bmpRef = softMap.remove(key);return bmpRef == null ? null : bmpRef.get();}@Overridepublic Collection<String> keys() {synchronized (softMap) {return new HashSet<String>(softMap.keySet());}}@Overridepublic void clear() {softMap.clear();}/** Creates {@linkplain Reference not strong} reference of value */protected abstract Reference<Bitmap> createReference(Bitmap value);}


增加了一个softMap的成员变量,实现了MemoryCache对softMap的操作,并且增加了一个Reference<Bitmap> createReference(Bitmap value)的抽象方法。


/******************************************************************************* * Copyright 2011-2014 Sergey Tarasevich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/package com.nostra13.universalimageloader.cache.memory;import android.graphics.Bitmap;import com.nostra13.universalimageloader.utils.L;import java.util.Collections;import java.util.LinkedList;import java.util.List;import java.util.concurrent.atomic.AtomicInteger;/** * Limited cache. Provides object storing. Size of all stored bitmaps will not to exceed size limit ( * {@link #getSizeLimit()}).<br /> * <br /> * <b>NOTE:</b> This cache uses strong and weak references for stored Bitmaps. Strong references - for limited count of * Bitmaps (depends on cache size), weak references - for all other cached Bitmaps. * * @author Sergey Tarasevich (nostra13[at]gmail[dot]com) * @see BaseMemoryCache * @since 1.0.0 */public abstract class LimitedMemoryCache extends BaseMemoryCache {private static final int MAX_NORMAL_CACHE_SIZE_IN_MB = 16;private static final int MAX_NORMAL_CACHE_SIZE = MAX_NORMAL_CACHE_SIZE_IN_MB * 1024 * 1024;private final int sizeLimit;private final AtomicInteger cacheSize;/** * Contains strong references to stored objects. Each next object is added last. If hard cache size will exceed * limit then first object is deleted (but it continue exist at {@link #softMap} and can be collected by GC at any * time) */private final List<Bitmap> hardCache = Collections.synchronizedList(new LinkedList<Bitmap>());/** @param sizeLimit Maximum size for cache (in bytes) */public LimitedMemoryCache(int sizeLimit) {this.sizeLimit = sizeLimit;cacheSize = new AtomicInteger();if (sizeLimit > MAX_NORMAL_CACHE_SIZE) {L.w("You set too large memory cache size (more than %1$d Mb)", MAX_NORMAL_CACHE_SIZE_IN_MB);}}@Overridepublic boolean put(String key, Bitmap value) {boolean putSuccessfully = false;// Try to add value to hard cacheint valueSize = getSize(value);int sizeLimit = getSizeLimit();int curCacheSize = cacheSize.get();if (valueSize < sizeLimit) {while (curCacheSize + valueSize > sizeLimit) {Bitmap removedValue = removeNext();if (hardCache.remove(removedValue)) {curCacheSize = cacheSize.addAndGet(-getSize(removedValue));}}hardCache.add(value);cacheSize.addAndGet(valueSize);putSuccessfully = true;}// Add value to soft cachesuper.put(key, value);return putSuccessfully;}@Overridepublic Bitmap remove(String key) {Bitmap value = super.get(key);if (value != null) {if (hardCache.remove(value)) {cacheSize.addAndGet(-getSize(value));}}return super.remove(key);}@Overridepublic void clear() {hardCache.clear();cacheSize.set(0);super.clear();}protected int getSizeLimit() {return sizeLimit;}protected abstract int getSize(Bitmap value);protected abstract Bitmap removeNext();}



接下来再看看LimitedMemoryCache,LimitedMemoryCache继承于BaseMemoryCache,并且有自己的抽象方法。

后面基于LimitedMemoryCache派生出来的类,我们可以注意到LimitedMemoryCache的put(String key, Bitmap value)方法里面调用到removeNext()方法,我们就可以通过改变removeNext()抽象方法来实现各个不同的LimitedMemoryCache。


这是FIFOLimitedMemoryCache的removeNext()方法。

@Overrideprotected Bitmap removeNext() {return queue.remove(0);}

直接将LinkedList的queue调用remove(0)方法从而实现FIFOLimitedMemoryCache。


这是LargestLimitedMemoryCache的removeNext()方法。

@Overrideprotected Bitmap removeNext() {Integer maxSize = null;Bitmap largestValue = null;Set<Entry<Bitmap, Integer>> entries = valueSizes.entrySet();synchronized (valueSizes) {for (Entry<Bitmap, Integer> entry : entries) {if (largestValue == null) {largestValue = entry.getKey();maxSize = entry.getValue();} else {Integer size = entry.getValue();if (size > maxSize) {maxSize = size;largestValue = entry.getKey();}}}}valueSizes.remove(largestValue);return largestValue;}

可以看到这里对valueSizes里面的元素做了对比找出最大的那个,然后返回出来。


LRULimitedMemoryCache的removeNext()方法。

@Overrideprotected Bitmap removeNext() {Bitmap mostLongUsedValue = null;synchronized (lruCache) {Iterator<Entry<String, Bitmap>> it = lruCache.entrySet().iterator();if (it.hasNext()) {Entry<String, Bitmap> entry = it.next();mostLongUsedValue = entry.getValue();it.remove();}}return mostLongUsedValue;}

这里用到了LinkedHashMap实现removeNext方法,从而实现LRU算法。


UsingFreqLimitedMemoryCache的removeNext()方法。

@Overrideprotected Bitmap removeNext() {Integer minUsageCount = null;Bitmap leastUsedValue = null;Set<Entry<Bitmap, Integer>> entries = usingCounts.entrySet();synchronized (usingCounts) {for (Entry<Bitmap, Integer> entry : entries) {if (leastUsedValue == null) {leastUsedValue = entry.getKey();minUsageCount = entry.getValue();} else {Integer lastValueUsage = entry.getValue();if (lastValueUsage < minUsageCount) {minUsageCount = lastValueUsage;leastUsedValue = entry.getKey();}}}}usingCounts.remove(leastUsedValue);return leastUsedValue;}

这里使用的是以Bitmap和Integer为键值对的Map,Integer记录了Bitmap的使用频率,removeNext里面查找最少使用频率,从而删除它。


总之MemoryCache部分的接口设计得挺好的,值得我们学习,有关内存缓存部分就说到这里。

0 0
原创粉丝点击