프로그래밍/안드로이드

안드로이드 - listView 항목에 Audio Albumart(thumbnail)을 지연 없이 나타내기 LinkedHashMap과 SoftReference사용 [캐시 처리]

가카리 2013. 12. 7. 21:19
반응형

LinkedHashMap과  SoftReference사용 Cache처리를 하는 로직이다.

한번 디스크에서 읽은 bitmap을 키값에 대응하여 저장한다.

인터넷의 아래 소스를 퍼왔다.


http://code.google.com/p/android-imagedownloader/source/browse/trunk/src/com/example/android/imagedownloader/ImageDownloader.java


구조는 LinkedHashMap을 사용한 HARD CASH와 SoftReference를 사용하여 메모리가 부족할때 

GC의 대상이 될수 있도록 한 HashMap 2가지가 유기적으로 동작한다.


private static final int HARD_CACHE_CAPACITY = 10;


private final HashMap<Long, Bitmap> sHardBitmapCache = new LinkedHashMap<Long, Bitmap>(

HARD_CACHE_CAPACITY / 2, 0.75f, true) {

@Override

protected boolean removeEldestEntry(

LinkedHashMap.Entry<Long, Bitmap> eldest) {

if (size() > HARD_CACHE_CAPACITY) {

// Entries push-out of hard reference cache are transferred to

// soft reference cache

sSoftBitmapCache.put(eldest.getKey(),

new SoftReference<Bitmap>(eldest.getValue()));

return true;

} else

return false;

}

};

 

// Soft cache for bitmaps kicked out of hard cache

private final static ConcurrentHashMap<Long, SoftReference<Bitmap>> sSoftBitmapCache = new ConcurrentHashMap<Long, SoftReference<Bitmap>>(

HARD_CACHE_CAPACITY / 2);

 


removeEldestEntry  함수는 LinkedHashMap 에 put할 경우 자동 호출되는 명령어로

true를 호출하게 되면 내부적으로 가장 먼저 들어왔던 항목을 버리도록 되어있다.

 

removeEldestEntry 함수를 Override하여 HARD_CACHE_CAPACITY 보다 사이즈가

커졌을 경우 sSoftBitmapCache에 넣도록 구현했다. 이후 true를 return했으므로 sHardBitmapCache 에

가장 먼저 들어왔던 항목은 삭제된다.

public void addBitmapToCache(Long id, Bitmap bitmap) {

LOG.i(CLASSNAME, "addBitmapToCache id : "+id+" , bitmap : "+bitmap);

LOG.i(CLASSNAME, "addBitmapToCache sHardBitmapCache.size() : "+sHardBitmapCache.size()+" , sSoftBitmapCache.size() : "+sSoftBitmapCache.size());

if (bitmap != null) {

synchronized (sHardBitmapCache) {

sHardBitmapCache.put(id, bitmap);

}

}

}


sHardBitmapCache 에 데이터를 넣는다.


public Bitmap getBitmapFromCache(long id) {

LOG.i(CLASSNAME, "getBitmapFromCache id : "+id);

LOG.i(CLASSNAME, "getBitmapFromCache sHardBitmapCache.size() : "+sHardBitmapCache.size()+" , sSoftBitmapCache.size() : "+sSoftBitmapCache.size());

synchronized (sHardBitmapCache) {

final Bitmap bitmap = sHardBitmapCache.get(id);

if (bitmap != null) {

// Bitmap found in hard cache

// Move element to first position, so that it is removed last

sHardBitmapCache.remove(id);

sHardBitmapCache.put(id, bitmap);

return bitmap;

}

}


// Then try the soft reference cache

SoftReference<Bitmap> bitmapReference = sSoftBitmapCache.get(id);

if (bitmapReference != null) {

final Bitmap bitmap = bitmapReference.get();

if (bitmap != null) {

// Bitmap found in soft cache

return bitmap;

} else {

// Soft reference has been Garbage Collected

sSoftBitmapCache.remove(id);

}

}

return null;

}

구현된 getBitmapFromCache 함수를 사용하여 Cache에 해당 키값에 대한 데이터가 있으면 가져온다.

sHardBitmapCache  remove하고 다시 put하는 동작으로 최근에 사용된 데이터가 항상 최신을 유지하도록 한다. 앞서 Override한 removeEldestEntry 함수 덕분에 사용하지 않는 데이터는 쓰다보면 삭제되게 되어있다.

sHardBitmapCache에 찾고자 하는 데이터가 없다면 sSoftBitmapCache 를 검색한다.



** Thumbnail을 가져오기 위해 기 구현된 AsyncTask를 상속받아 구현한 객체를 생성하기 전에

위 자료 구조를 사용하여 Map에 저장된 bitmap을 가져오면 반응 속도를 향상 시킬수 있다.

그러나  Memory Leak에 대해서는 관심이 필요할 것으로 보인다.



출처 : http://jijs.tistory.com/entry/listView-%ED%95%AD%EB%AA%A9%EC%97%90-Audio-Albumartthumbnail%EC%9D%84-%EC%A7%80%EC%97%B0-%EC%97%86%EC%9D%B4-%EB%82%98%ED%83%80%EB%82%B4%EA%B8%B0-LinkedHashMap%EA%B3%BC-SoftReference%EC%82%AC%EC%9A%A9-%EC%BA%90%EC%8B%9C-%EC%B2%98%EB%A6%AC