Glide
쉽게 이미지를 로드하고 이미지 캐싱까지 지원해주는 이미지 로드 라이브러리이다.
사용법은 with()
에 Context
를 지정하고, load()
에 불러올 이미지를 지정하고, into()
에 불러온 이미지를 바인딩할 ImageView
를 지정하면 된다.
fun ImageView.bindImage(url: String) =
Glide.with(this)
.load(url)
.into(this)
Glide
는 이미지 로드 뿐만 아니라 다양한 처리를 위한 옵션들을 제공해준다.
fun ImageView.bindImage(url: String) =
Glide.with(this)
.load(url)
.override(100, 100)
.thumbnail(0.1f) // 0.1f = 10% 화질
.placeholder(R.drawable.holder)
.error(R.drawable.error)
.fallback(R.drawable.empty)
.into(this)
override()
를 사용하여 이미지의 크기를 조절해서 로드할 수 있는데, 만약 불러오는 이미지가 너무 클 경우 이미지 로드 속도가 느려지거나OutOfMemory
가 발생하는 것을 방지할 수 있다.thumbnail()
을 사용하여 먼저 화질이 낮은 이미지를 보여주고 이후 원본 이미지를 보여줄 수 있다.placeholder()
를 사용하여 이미지가 로드되기 전 표시되는 이미지를 지정할 수 있다.error()
를 사용하여 이미지 로드에 실패했을 때 표시되는 이미지를 지정할 수 있다.fallback()
을 사용하여 로드할 이미지의URL
이null
인 경우 표시되는 이미지를 지정할 수 있다.
Glide
는 이미지 요청에 대한 콜백 리스너도 제공해준다.
val listener = object: RequestListener<Drawable> {
override fun onResourceReady(
resource: Drawable?,
model: Any?,
target: Target<Drawable>?,
dataSource: DataSource?,
isFirstResource: Boolean)
: Boolean {
/* 성공 */
}
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<Drawable>?,
isFirstResource: Boolean
): Boolean {
/* 실패 */
}
}
Glide
를 사용하는 ImageView
가 여러 개이고 모두 동일한 Option
을 공유한다면 RequestOptions
객체를 통해 옵션을 공유할 수 있다.
val option = RequestOptions()
.override(100, 100)
.placeholder(R.drawable.error)
.error(R.drawable.error)
.diskCacheStrategy(DiskCacheStrategy.ALL)
Glide.with(this).load(url).apply(option).into(this)
이미지 캐싱
동일한 URL
에서 반복적으로 이미지를 불러오게 된다면 이미지 크기가 작은 상황에서는 문제가 없지만, 큰 이미지를 받아오는 상황이라면 매번 수 초의 시간과 상당한 양의 메모리가 할당되기 때문에 성능적으로 좋지 않은데, 이러한 문제를 해결하기 위한 방법이 이미지 캐싱이다.
이미지 캐싱은 URL
에서 가져온 이미지를 캐시에 저장해서 동일한 URL
을 요청했을 때 재요청 없이 캐시에 저장한 이미지를 로드하는 방법으로, Glide
에서는 이를 쉽게 사용할 수 있도록 지원해준다.
Glide
의 이미지 캐시 처리는 리소스가 메모리에 있는지 확인하고, 그 다음으로 이미지가 디스크에 있는지 확인하고, 만약 이미지를 찾지 못한다면 Glide
는 원본 소스로 돌아가 데이터를 검색한다.
Glide
는 기본적으로 메모리 캐싱을 하기 때문에 메모리 캐싱을 위해 추가적으로 설정할 것은 없다.
하지만 URL 이미지 로드 시 한 번 로드한 이미지는 캐싱되어 서버에서 해당 이미지를 변경해도 이미지가 갱신되지 않는데, 이런 경우 skipMemoryCache(true)
로 메모리 캐시를 사용하지 않을 수 있다.
fun ImageView.bindImage(url: String) =
Glide.with(this)
.load(url)
.skipMemoryCache(true)
.into(this)
Glide
는 기본적으로 디스크 캐싱을 수행하며 메모리 캐싱과 동일하게 동작하고 5가지의 DiskCacheStrategy
를 지원한다.
fun ImageView.bindImage(url: String) =
Glide.with(this)
.load(url)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.into(this)
DiskCacheStrategy.ALL
은 모든 이미지를 캐싱하는 전략이다.DiskCacheStrategy.AUTOMATIC
은Resource
를 기반으로 전략적인 캐싱을 하는 전략이다.DiskCacheStrategy.DATA
는 원본 이미지만 캐싱하는 전략이다.DiskCacheStrategy.RESOURCE
는 해상도를 줄인 이미지만 캐싱하는 전략이다.DiskCacheStrategy.NONE
은 디스크 캐싱을 안하는 전략이다.
이미지가 메모리 캐시 또는 디스크 캐시에서 발견되면 로드 되고, 없다면 로드가 되지 않는 옵션도 지원한다.
fun ImageView.bindImage(url: String) =
Glide.with(this)
.load(url)
.onlyRetrieveFromCache(true)
.into(this)
LRU Cashe
LRU
는 Least
Recently
Used
(최근에 가장 적게 참조됨)의 약자로, LRU
Cache
는 제한된 사이즈에서 참조된지 가장 오래된 객체를 제거하는 데이터 구조로, 자주 참조되는 객체일 수록 빠르게 캐시를 통해 객체에 접근할 수 있다.
put(Key, Value)
를 통해 캐싱을 시도 할 수 있으며, 캐시에 있는 데이터를 참조할 때는 get(Key)
을 사용하면 된다.
val cache = LruCache<String, Int>(5).apply { // maxSize = 5
put("A",0) // [A]
put("B",0) // [A, B]
put("C",0) // [A, B, C]
put("D",0) // [A, B, C, D]
put("E",0) // [A, B, C, D, E] - A 부터 E 까지 캐싱 완료
put("F",0) // [B, C, D, E, F] - F 를 캐싱하면, 캐시 사이즈를 초과하므로 최근에 가장 적게 참조된 A 는 제거됨
put("D",0) // [B, C, E, F, D] - 캐시에 이미 포함된 키인 D 를 다시 캐싱을 하면 D 가 가장 최근에 참조된 키이므로 내부에서 데이터를 재배열하고 최근 참조된 상태로 변경됨
get("C") // [B, E, F, D, C] - 키가 C 인 값을 얻고자 하면 C 가 가장 최근에 참조된 키이므로 다시 내부에서 데이터를 재배열 하고 최근 참조된 상태로 변경됨
}
LRU
Cache
를 사용하는 대표적인 예가 Bitmap
캐싱으로, RecyclerView
에서 대량의 이미지를 한번에 로드하고 스크롤하여 재사용되는 경우 LRU
Cache
의 사용은 성능 향상에 많은 도움이 된다.
많은 Bitmap
을 메모리에 캐시하는 것은 부담될 수 있으므로 DiskLruCache
와 같은 디스크 캐싱을 같이 사용하면 좀 더 메모리 부담을 줄일 수 있으며, 이러한 Bitmap
캐싱을 최적화하여 제공하고 있는 라이브러리가 Glide
이다.