Android 이미지 캐 시 및 캐 시 알고리즘 (Universal - Image - Loader)
캐 시 는 메모리 회수 메커니즘 과 관련 이 있 습 니 다. 자바 에는 쓰레기 회수 (gc) 와 관련 된 네 가지 인용 이 있 습 니 다. 강 한 인용 (StrongReference), 부 드 러 운 인용 (SoftReference), 약 한 인용 (WeakReference) 과 허 인용 (PhantomReference) 이 있 습 니 다.
강 인용 (StrongReference)
강 한 인용 은 가장 보편적 인 인용 입 니 다. 자바 에서 new 키 워드 를 사용 하여 생 성 된 대상 은 강 한 인용 입 니 다. 강 한 인용 에 대해 자바 쓰레기 회수 체 제 는 회수 하지 않 습 니 다. 메모리 가 부족 할 때 자바 가상 기 는 OutOf Memory Error 오 류 를 버 릴 지 언 정 강 한 인용 대상 을 함부로 회수 하지 않 습 니 다.
소프트 참조 (소프트 참조)
소프트 인용 에 대해 서 는 메모리 가 충분 할 때 소프트 인용 대상 을 회수 하지 않 지만 메모리 공간 이 부족 할 때 이 대상 을 회수 합 니 다.
약 인용 (WeakReference)
약 한 인용 은 소프트 인용 에 비해 회수 메커니즘 에 의 해 회수 되 기 쉽다. 쓰레기 회수 메커니즘 이 메모리 공간 을 스 캔 할 때 약 한 인용 대상 을 발견 하면 현재 메모리 가 충분 하 든 상 관 없 이 즉시 회수 하여 메모리 공간 을 방출 한다.
가상 인용 (PhantomReference)
가상 인용 은 다른 인용 과 달리 대상 의 생명 주 기 를 결정 하지 않 는 다.만약 한 대상 이 허위 인용 만 가지 고 있다 면, 그것 은 아무런 인용 도 없 는 것 과 마찬가지 로 언제든지 쓰레기 회수 기 에 의 해 회 수 될 수 있다.
Universal - Image - Loader 의 캐 시 메커니즘
1. LRU (Least Recently Used) 최근 가장 오랫동안 페이지 교체 알고리즘 을 사용 하지 않 음
LRU 는 운영 체제 에서 페이지 바 꾸 기 알고리즘 의 하나 로, 각 페이지 에 대해 마지막 으로 방문 한 이후 겪 은 시간 t 를 기록 하기 위해 시간 필드 를 설정 하 는 것 이 핵심 이다.
2. Universal - Image - Loader 의 캐 시 메커니즘
(1) 강 인용 캐 시 만 사용 합 니 다.
LruMemory Cache (LRU 알고리즘 을 사용 하고 캐 시 대상 은 bitmap 의 강 한 참조)
(2) 강 한 인용 과 약 한 인용 이 결 합 된 캐 시 를 사용 합 니 다.
UsingFreqLimited Memory Cache (캐 시 된 그림 의 전체 수량 이 한정 치 를 초과 하면 사용 빈도 가 가장 작은 bitmap 를 삭제 합 니 다)
LRULimited Memory Cache (이것 도 lru 알고리즘 을 사용 합 니 다. LruMemory Cache 와 달리 그 가 캐 시 한 것 은 bitmap 의 약 한 인용 입 니 다)
FIFOLimited Memory Cache (먼저 나 온 캐 시 정책, 설정 값 을 초과 하면 캐 시 에 가장 먼저 가입 한 bitmap 을 삭제 합 니 다)
Largest Limited Memory Cache (캐 시 한정 치 를 초과 하면 최대 bitmap 대상 을 삭제 합 니 다)
Limited Age Memory Cache (bitmap 가 캐 시 에 가입 하 는 시간 이 우리 가 설정 한 값 을 초과 하면 삭제 합 니 다)
(3) 약 한 인용 캐 시 만 사용
Weak Memory Cache (이 종류의 캐 시 bitmap 의 총 크기 는 제한 이 없고 유일 하 게 부족 한 점 은 불안정 하 며 캐 시 된 그림 은 쉽게 회수 된다)
LruMemory Cache 소스 코드 분석
package com.nostra13.universalimageloader.cache.memory.impl;
import android.graphics.Bitmap;
import com.nostra13.universalimageloader.cache.memory.MemoryCache;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* A cache that holds strong references to a limited number of Bitmaps. Each time a Bitmap is accessed, it is moved to
* the head of a queue. When a Bitmap is added to a full cache, the Bitmap at the end of that queue is evicted and may
* become eligible for garbage collection.
*
* NOTE: This cache uses only strong references for stored Bitmaps.
*
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
* @since 1.8.1
*/
public class LruMemoryCache implements MemoryCache {
private final LinkedHashMap map;
private final int maxSize;
/** Size of this cache in bytes */
private int size;
/** @param maxSize Maximum sum of the sizes of the Bitmaps in this cache */
public LruMemoryCache(int maxSize) {
if (maxSize <= 0) {
throw new IllegalArgumentException("maxSize <= 0");
}
this.maxSize = maxSize;
this.map = new LinkedHashMap(0, 0.75f, true);
}
/**
* Returns the Bitmap for {@code key} if it exists in the cache. If a Bitmap was returned, it is moved to the head
* of the queue. This returns null if a Bitmap is not cached.
*/
@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;
}
/**
* Remove the eldest entries until the total of remaining entries is at or below the requested size.
*
* @param maxSize the maximum size of the cache before returning. May be -1 to evict even 0-sized elements.
*/
private void trimToSize(int maxSize) {
while (true) {
String key;
Bitmap value;
synchronized (this) {
if (size < 0 || (map.isEmpty() && size != 0)) {
throw new IllegalStateException(getClass().getName() + ".sizeOf() is reporting inconsistent results!");
}
if (size <= maxSize || map.isEmpty()) {
break;
}
Map.Entry toEvict = map.entrySet().iterator().next();
if (toEvict == null) {
break;
}
key = toEvict.getKey();
value = toEvict.getValue();
map.remove(key);
size -= sizeOf(key, value);
}
}
}
/** Removes the entry for {@code key} if it exists. */
@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;
}
}
@Override
public Collection keys() {
synchronized (this) {
return new HashSet(map.keySet());
}
}
@Override
public void clear() {
trimToSize(-1); // -1 will evict 0-sized elements
}
/**
* Returns the size {@code Bitmap} in bytes.
*
* An entry's size must not change while it is in the cache.
*/
private int sizeOf(String key, Bitmap value) {
return value.getRowBytes() * value.getHeight();
}
@Override
public synchronized final String toString() {
return String.format("LruCache[maxSize=%d]", maxSize);
}
}
원본 코드 에서 LinkedHashMap 은 LRU 알고리즘 의 캐 시 로 서 LinkedHashMap 은 HashMap 의 하위 클래스 로 삽입 순 서 를 유지 합 니 다. LinkedHashMap 은 HashMap 과 다른 점 은 후자 가 모든 항목 에서 실행 되 는 이중 링크 목록 을 유지 하고 있 습 니 다.이 링크 목록 은 교체 순 서 를 정의 합 니 다. 이 교체 순 서 는 삽입 순서 나 방문 순서 일 수 있 습 니 다.
기본 값 은 삽입 순서에 따라 정렬 합 니 다. 방문 순서에 따라 정렬 할 것 을 지정 하면 get 방법 을 호출 한 후에 이번 방문 요 소 를 링크 끝 에 옮 기 고 계속 방문 하면 방문 순서에 따라 정렬 하 는 링크 를 만 들 수 있 습 니 다.removeEldestEntry 방법 을 다시 쓸 수 있 습 니 다. true 값 이 지정 한 삽입 요 소 를 되 돌려 줄 때 가장 오래된 요 소 를 제거 할 수 있 습 니 다.
this.map = new LinkedHashMap(0, 0.75f, true);
구조 방법 에서 첫 번 째 매개 변 수 는 링크 드 HashMap 의 초기 용량 을 대표 하고 두 번 째 매개 변 수 는 0.75f 는 로드 인자 이 며 세 번 째 매개 변 수 는 방문 순서 이 며 기본 값 은 false 즉 삽입 순서 이 고 true 는 방문 순서 입 니 다.LruMemory Cache 에 서 는 모든 bitmap 의 size 와 size 가 설 정 된 max Size 를 초과 하면 최근 에 사용 하지 않 은 그림 캐 시 를 삭제 합 니 다.
소스 코드 의 put 방법 에서 HashMap 의 put 방법 을 호출 하 였 습 니 다.
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
for (Entry e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}
void recordAccess(HashMap m) {
LinkedHashMap lm = (LinkedHashMap)m;
// LinkedHashMap
if (lm.accessOrder) {
lm.modCount++;
//
remove();
//
addBefore(lm.header);
}
}
/**
* ,
*/
private void remove() {
before.after = after;
after.before = before;
}
/**
* existingEntry
*/
private void addBefore(Entry existingEntry) {
after = existingEntry;
before = existingEntry.before;
before.after = this;
after.before = this;
}
HashMap 에서 put 방법 원본 코드 입 니 다. HashMap 에 이 value 가 존재 할 때 이 value 를 되 돌려 줍 니 다. 그렇지 않 으 면 null 로 돌아 갑 니 다. 따라서
map.put(key, value)
반환 값 이 비어 있 지 않 을 때 새로 추 가 된 그림 size 를 빼 야 합 니 다.null 로 되 돌아 갈 때 비트 맵 을 링크 드 HashMap 에 추가 하고 비트 맵 으로 되 돌아 갈 때 이 비트 맵 을 직접 사용 합 니 다.recordAccess(HashMap m)
HashMap 의 put 와 get 방법 에서 이 방법 을 호출 합 니 다. HashMap 에서 이 방법 은 비어 있 습 니 다. LinkedHashMap 에서 방문 순서에 따라 정렬 할 때 이 방법 은 현재 노드 를 링크 꼬리 (머리 노드 의 앞 노드) 에 삽입 합 니 다. 그렇지 않 으 면 아무것도 하지 않 습 니 다 (최근 에 사용 한 bitmap 은 양 방향 링크 의 꼬리 로 이동 합 니 다).LRU 알고리즘 구현 의 핵심 은
private void trimToSize(int maxSize)
함수 에서 현재 size 가 maxSize 보다 큰 지 여 부 를 계속 판단 하 는 것 입 니 다. maxSize 를 초과 하면 LinkedHashMap 의 첫 번 째 요 소 를 삭제 합 니 다. 이것 이 바로 최근 에 가장 오래 사용 하지 않 은 bitmap 입 니 다.LinkedHashMap 을 사용 하면 LRU 알고리즘 을 기반 으로 한 캐 시 를 쉽게 만 들 수 있 습 니 다.
UsingFreq Limited Memory Cache 소스 코드 분석
/*******************************************************************************
* 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> softMap = Collections.synchronizedMap(new HashMap>());
@Override
public Bitmap get(String key) {
Bitmap result = null;
Reference reference = softMap.get(key);
if (reference != null) {
result = reference.get();
}
return result;
}
@Override
public boolean put(String key, Bitmap value) {
softMap.put(key, createReference(value));
return true;
}
@Override
public Bitmap remove(String key) {
Reference bmpRef = softMap.remove(key);
return bmpRef == null ? null : bmpRef.get();
}
@Override
public Collection keys() {
synchronized (softMap) {
return new HashSet(softMap.keySet());
}
}
@Override
public void clear() {
softMap.clear();
}
/** Creates {@linkplain Reference not strong} reference of value */
protected abstract Reference 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()}).
*
* NOTE: 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 hardCache = Collections.synchronizedList(new LinkedList());
/** @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);
}
}
@Override
public boolean put(String key, Bitmap value) {
boolean putSuccessfully = false;
// Try to add value to hard cache
int 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 cache
super.put(key, value);
return putSuccessfully;
}
@Override
public Bitmap remove(String key) {
Bitmap value = super.get(key);
if (value != null) {
if (hardCache.remove(value)) {
cacheSize.addAndGet(-getSize(value));
}
}
return super.remove(key);
}
@Override
public void clear() {
hardCache.clear();
cacheSize.set(0);
super.clear();
}
protected int getSizeLimit() {
return sizeLimit;
}
protected abstract int getSize(Bitmap value);
protected abstract Bitmap removeNext();
}
/*******************************************************************************
* 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.impl;
import android.graphics.Bitmap;
import com.nostra13.universalimageloader.cache.memory.LimitedMemoryCache;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/**
* Limited {@link Bitmap bitmap} cache. Provides {@link Bitmap bitmaps} storing. Size of all stored bitmaps will not to
* exceed size limit. When cache reaches limit size then the bitmap which used the least frequently is deleted from
* cache.
*
* NOTE: 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)
* @since 1.0.0
*/
public class UsingFreqLimitedMemoryCache extends LimitedMemoryCache {
/**
* Contains strong references to stored objects (keys) and last object usage date (in milliseconds). If hard cache
* size will exceed limit then object with the least frequently usage is deleted (but it continue exist at
* {@link #softMap} and can be collected by GC at any time)
*/
private final Map usingCounts = Collections.synchronizedMap(new HashMap());
public UsingFreqLimitedMemoryCache(int sizeLimit) {
super(sizeLimit);
}
@Override
public boolean put(String key, Bitmap value) {
if (super.put(key, value)) {
usingCounts.put(value, 0);
return true;
} else {
return false;
}
}
@Override
public Bitmap get(String key) {
Bitmap value = super.get(key);
// Increment usage count for value if value is contained in hardCahe
if (value != null) {
Integer usageCount = usingCounts.get(value);
if (usageCount != null) {
usingCounts.put(value, usageCount + 1);
}
}
return value;
}
@Override
public Bitmap remove(String key) {
Bitmap value = super.get(key);
if (value != null) {
usingCounts.remove(value);
}
return super.remove(key);
}
@Override
public void clear() {
usingCounts.clear();
super.clear();
}
@Override
protected int getSize(Bitmap value) {
return value.getRowBytes() * value.getHeight();
}
@Override
protected Bitmap removeNext() {
Integer minUsageCount = null;
Bitmap leastUsedValue = null;
Set> entries = usingCounts.entrySet();
synchronized (usingCounts) {
for (Entry 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;
}
@Override
protected Reference createReference(Bitmap value) {
return new WeakReference(value);
}
}
UsingFreqLimited Memory Cache 는 Limited Memory Cach 에서 물 려 받 았 고, Limited Memory Cach 는 BaseMemory Cache 에서 물 려 받 았 다.BaseMemory Cache 에서
Map> softMap
소프트 인용 형식 bitmap 를 포함 한 softpap 을 유지 하고 softpap 의 get, put, remove, clear 방법 을 정의 합 니 다.Limited Memory Cache 는 BaseMemory Cache 를 계승 합 니 다. 그 중에서
MAX_NORMAL_CACHE_SIZE_IN_MB
, MAX_NORMAL_CACHE_SIZE
, 메모리 크기 제한 size Limit 와 List hardCache (이 알고리즘 을 유지 하 는 bitmap 목록) 를 정의 합 니 다.put 작업 을 할 때 먼저 put 의 bitmap 가 제 한 된 size Limit 보다 큰 지 판단 합 니 다. size Limit 보다 작 으 면 현재 캐 시 된 cache Size 를 순환 적 으로 판단 합 니 다.(AtomicInteger 는 원자 조작 을 제공 하 는 Integer 클래스 로 스 레 드 를 통 해 안전하게 작 동 합 니 다. AtomicInteger 는 원자 조작 을 제공 하여 Integer 를 사용 하기 때문에 높 은 병행 상황 에서 사용 하기에 매우 적합 합 니 다.) put 할 bitmap 의 size 가 sizeLimit 보다 큰 지, sizeLimit 보다 크 면 알고리즘 을 사용 하여 최소 비트 맵 을 삭제 합 니 다.removeNext () 는 UsingFreqLimited Memory Cache 에서 이 루어 집 니 다. Map usingCounts 를 사용 하여 메모리 에 있 는 bitmap 의 사용 횟수 를 저장 합 니 다. removeNext () 방법 을 호출 할 때 Map usingCounts 를 옮 겨 다 니 며 사용 횟수 가 가장 적은 bitmap 를 찾 아 되 돌려 줍 니 다.
FIFOLimited Memory Cache 소스 코드 분석
/*******************************************************************************
* 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.impl;
import android.graphics.Bitmap;
import com.nostra13.universalimageloader.cache.memory.LimitedMemoryCache;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
/**
* Limited {@link Bitmap bitmap} cache. Provides {@link Bitmap bitmaps} storing. Size of all stored bitmaps will not to
* exceed size limit. When cache reaches limit size then cache clearing is processed by FIFO principle.
*
* NOTE: 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)
* @since 1.0.0
*/
public class FIFOLimitedMemoryCache extends LimitedMemoryCache {
private final List queue = Collections.synchronizedList(new LinkedList());
public FIFOLimitedMemoryCache(int sizeLimit) {
super(sizeLimit);
}
@Override
public boolean put(String key, Bitmap value) {
if (super.put(key, value)) {
queue.add(value);
return true;
} else {
return false;
}
}
@Override
public Bitmap remove(String key) {
Bitmap value = super.get(key);
if (value != null) {
queue.remove(value);
}
return super.remove(key);
}
@Override
public void clear() {
queue.clear();
super.clear();
}
@Override
protected int getSize(Bitmap value) {
return value.getRowBytes() * value.getHeight();
}
@Override
protected Bitmap removeNext() {
return queue.remove(0);
}
@Override
protected Reference createReference(Bitmap value) {
return new WeakReference(value);
}
}
FIFOLimited Memory Cache 도 Limited Memory Cache 를 계승 하고 하나의 LinkedList 를 유지 했다. Array List 에 비해 LinkedList 에는 양 방향 순환 링크 가 포함 되 어 있 고 스 택 과 대기 열 과 유사 한 조작 을 제공 했다.
LinkedList 의 add 방법:
public boolean add(E e) {
addBefore(e, header);
return true;
}
private Entry addBefore(E e, Entry entry) {
Entry newEntry = new Entry(e, entry, entry.previous);
newEntry.previous.next = newEntry;
newEntry.next.previous = newEntry;
size++;
modCount++;
return newEntry;
}
링크 드 리스트 에 요 소 를 삽입 할 때 header 뒤에 요 소 를 삽입 합 니 다
addBefore(e, header);
. 요 소 를 링크 의 끝 에 삽입 합 니 다.public E remove(int index) {
return remove(entry(index));
}
private Entry entry(int index) {
if (index < 0 || index >= size)
throw new IndexOutOfBoundsException("Index: "+index+
", Size: "+size);
Entry e = header;
//
if (index < (size >> 1)) {
for (int i = 0; i <= index; i++)
e = e.next;
} else {
// header , ,header previous , header
for (int i = size; i > index; i--)
e = e.previous;
}
return e;
}
FIFOLimited Memory Cache 의 removeNext () 방법 중 quue. remove (0); 양 방향 순환 목록 의 첫 번 째 요 소 를 삭제 합 니 다. 이 를 통 해 알 수 있 듯 이 요 소 를 삽입 할 때 양 방향 순환 목록 의 끝 에 새 요 소 를 삽입 하고 삭제 할 때 목록 의 첫 번 째 요 소 를 삭제 하 는 것 입 니 다. 이 밖 에 Largest Limited Memory Cache 와 Limited Age Memory Cach 는 모두 Limited Memory Cache 를 계승 하여 강 한 인용 과 약 한 인용 이 결 합 된 캐 시 입 니 다.BaseMemory Cache 에서 부 드 러 운 인용 HashMap > () 을 유 지 했 기 때문에 Limited Memory Cache 에서 강 한 인용 링크 드 List () 를 유 지 했 습 니 다. 구체 적 인 실현 알고리즘 이 다 를 뿐 입 니 다.
Weak Memory Cache 소스 코드 분석
/*******************************************************************************
* 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.impl;
import android.graphics.Bitmap;
import com.nostra13.universalimageloader.cache.memory.BaseMemoryCache;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
/**
* Memory cache with {@linkplain WeakReference weak references} to {@linkplain android.graphics.Bitmap bitmaps}
*
* NOTE: This cache uses only weak references for stored Bitmaps.
*
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
* @since 1.5.3
*/
public class WeakMemoryCache extends BaseMemoryCache {
@Override
protected Reference createReference(Bitmap value) {
return new WeakReference(value);
}
}
Weak Memory Cache 는 BaseMemory Cache 를 계승 하여 Weak Reference 를 되 돌려 주 고 다른 방법 으로 부모 방법 을 사용 합 니 다.
참고 글:http://blog.csdn.net/xiaanming/article/details/27525741 http://www.cnblogs.com/children/archive/2012/10/02/2710624.html http://blog.csdn.net/jzhf2012/article/details/8540543
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.