(안드로이드) 이미지 로딩 처리(메모리캐시, 디스크캐시)
*안드로이드에서는 LruCache를 제공한다. LruCache는 LinkedHashMap을 사용하여 최근에 사용된 object의 strong reference를 보관하고 있다가 정해진 사이즈를 넘어가게 되면 가장 최근에 사용되지 않은 놈부터 쫒아내는 LRU알고리즘을 사용하는 메모리 캐시다.
예전에는 bitmapcache에 SoftReference나 WeakReference를 사용하는 방식을 썻으나 안드로이드 2.3부터 가비지 콜렉터가 공격적으로 이놈들의 메모리를 가비지 콜렉팅하면서 몹쓸 방법이 되었다. 게다가 이 방법은 3.0이전 버전에서 매모리 해제를 제대로 못해 크래쉬 문제도 있다.
그러나 LruCache를 사용해보겠다. LruCache의 캐시 사이즈를 정하기 위해서 고려할 사항
예전에는 bitmapcache에 SoftReference나 WeakReference를 사용하는 방식을 썻으나 안드로이드 2.3부터 가비지 콜렉터가 공격적으로 이놈들의 메모리를 가비지 콜렉팅하면서 몹쓸 방법이 되었다. 게다가 이 방법은 3.0이전 버전에서 매모리 해제를 제대로 못해 크래쉬 문제도 있다.
그러나 LruCache를 사용해보겠다. LruCache의 캐시 사이즈를 정하기 위해서 고려할 사항
- 앱에서 앞으로 메모리를 얼마나 사용해야 하는가?
- 얼마나 많은 이미지들이 한 화면에 보여질 것인가? 얼마나 많은 이미지들이 다음에 보여주기 위해 준비되어야 하는가?
- 화면 해상도가 어떻게 되는가?
- 각 이미지마다 메모리를 얼마나 차지하는가?
- 이미지는 얼마나 자주 액세스 되는가?
- 질보다 양? 양보다 질? 어떤 경우에는 많은 양의 저해상도 이미지를 미리 보여주고 백그라운드로 고해상도 이미지를 로드하는 방법이 좋을 수도 있다.
너무 캐시사이즈를 작게하면 오버헤드만 발생하고, 사이즈를 너무 크게하면 OutOfMemoryException을 보게 된다.
<아주 큰 비트맵을 효율적으로 로딩하기>
애플리케이션의 메모리 제한에 문제없이 비트맵을 로딩하는 방법.
이미지를 표시할 UI컴포넌트는 대체적으로 이미지보다 작게 표시된다. 이떄는 이미지의 원본사이즈가 아니라 표시될 컴포넌트의 크기에 맞게 로드하는것이 이득이다.
BitmapFactory클래스가 비트맵을 디코딩하기 위한 여러 메소드(decodeByteArray(), decodeFile(), decodeResource())들을 제공한다.
이 메소드들은 비트맵을 디코딩할 때 메모리할당을 시도하기 때문에 메모리 부족현상이 쉽게 발생한다.
메소드들에는 BitmapFactory.Options인자를 받을 수 있는데, inJustDecodeBounds를 true를 주어서 디코딩시 메모리할당을 피하면서 이미지의 가로/세로 사이즈를 아아낼 수 있다.
이를 이용해서 메모리 할당을 조절할 수 있다.
BitmapFactory.Options options=new BitmapFactory.Options();
options.inJustDecodeBounds=true;
BitmapFactory.decodeResource(getResources(),R.id.myimage,options);
예)
BitmapWorkerTask 또한 메모리캐시를 사용하는걸로 변경
<디스크 캐시 이용하기>
메모리 캐시는 빠르기는 하지만 메모리가 얼마 되지 않아 이것만 가지고는 부족하다.
그리고 전화가 오거나 하면 앱이 백그라운드로 가버리면서 캐시가 사라져 버리게 된다.
디스크 캐시를 사용하면 데이터가 지속적으로 남아있고 용량도 좀 더 많이 사용할 수 있다.
하지만 당연히 메모리 캐시보다 느리다. 그래도 네트워크에서 읽어들이는 것에 비해 훨씬 낫다.
그리고 ContentProvider을 사용하는게 자주 액세스 되는 이미지를 캐시에 저장하기에 좋다.
아래코드는 메모리캐시에 디스크 캐시를 축한 버전이다.
댓글
댓글 쓰기