Android 이미지 캐 시 및 캐 시 알고리즘 (Universal - Image - Loader)

28259 단어
메모리 캐 시
캐 시 는 메모리 회수 메커니즘 과 관련 이 있 습 니 다. 자바 에는 쓰레기 회수 (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

좋은 웹페이지 즐겨찾기