이번 글에서는 Glide 사용 시에 Cache Key를 커스텀해서 캐싱을 유도하는 방법을 소개하겠습니다.
ImageLoader로 안드로이드에서 많이 사용하는 Glide는 ImageUrl 기준으로 다운로드하며 캐싱됩니다.
Glide.with(this)
.load(/** imge url */)
.into(binding.imageView)
로드된 이미지가 어디에서 얻어졌는지도 RequestListener에 정의된 DataSource값으로 확인할 수 있습니다.
실제로 이미지 로드에 사용하는 load 함수에 전달할 수 있는 타입은 Bitmap/Drawable/String/Uri/File/Integer/Array<Byte>/Any 형태를 지원하고 있습니다. 다양한 형태로 전달된 데이터는 Glide에 미리 정의된 타입별로 처리를 정의한 RegistryFactory의 내용대로 동작합니다.
일반적으로 http/https로 시작하는 이미지 주소는 Glide 내부에서 몇 가지의 단계를 거쳐서 이미지가 읽어집니다.
UrlUriLoader를 디버깅하면 GlideUrl 인스턴스를 생성한 후, HttpGlideUrlLoader에 전달하는 것을 확인할 수 있습니다.
HttpGlideUrlLoader에서 사용되는 GlideUrl 클래스가 이번 글의 핵심 클래스입니다. 이번에 필요한 기능으로 (1) 이미지 캐시 키를 커스텀하면서 (2) 정상적으로 이미지를 호출해야 하는 2가지 조건이 필요합니다. GlideUrl 내부에 이번 내용에 관련된 중요한 함수를 찾을 수 있습니다.
open fun getCacheKey(): String
- 디스크 캐시 키로 사용할 문자열을 반환
open fun toStringUrl(): String
- http/https 요청을 만드는 데 사용할 수 있는 문자열 URL을 반환
그리고, GlideUrl이 구현하는 Key 인터페이스도 캐싱에 관련된 정의가 있습니다.
abstract fun equals(o: Any): Boolean
- 캐싱이 올바르게 작동하려면 구현에서 이 메서드와 hashCode를 구현해야 합니다.
abstract fun hashCode(): Int
- 캐싱이 올바르게 작동하려면 구현에서 이 메서드와 같음을 구현해야 합니다.
실제로 GlideUrl 클래스는 GlideUrl#getCacheKey를 사용하여 Key 인터페이스를 구현하고 있습니다.
public class GlideUrl implements Key {
...
@Override
public boolean equals(Object o) {
if (o instanceof GlideUrl) {
GlideUrl other = (GlideUrl) o;
return getCacheKey().equals(other.getCacheKey()) && headers.equals(other.headers);
}
return false;
}
@Override
public int hashCode() {
if (hashCode == 0) {
hashCode = getCacheKey().hashCode();
hashCode = 31 * hashCode + headers.hashCode();
}
return hashCode;
}
}
소스 출처 : https://github.com/bumptech/glide/blob/master/library/src/main/java/com/bumptech/glide/load/model/GlideUrl.java#L131-L147
앞서 UrlUriLoader에서 사용되는 GlideUrl에서 중요한 키 포인트인 getCacheKey 함수를 발견했습니다. 앞으로 할 작업은 매우 간단합니다. Glide에 커스텀 ModelLoader까지 구현하는 것도 방법이지만, 본 글에서는 가볍게 GlideUrl를 상속해서 해결하겠습니다.
class GlideUrlWithCacheKey(
imageUrl: String,
private val cacheKey: String
) : GlideUrl(imageUrl) {
override fun getCacheKey(): String = cacheKey // 생성자로 주입받은 별도 캐시 키를 활용
}
그리고, GlideUrlWithCacheKey 클래스를 사용해서 Glide를 사용하면 됩니다.
Glide.with(this)
.load(GlideUrlWithCacheKey(imageUrl = /** imge url */, cacheKey = /** Cache Key */))
.into(binding.imageView)
샘플 소스 : https://github.com/Pluu/GlideCacheKeySample
위 샘플은 두 개의 버튼에 각각 다른 Image Url과 동일한 캐시 키를 사용한 예제의 모습입니다. 최초 로드된 이미지를 기준으로 캐싱이 일어나므로 데이터 초기화한 후에는 다른 이미지가 캐싱되는 것을 볼 수 있습니다.
Glide에는 타입별로 어떤 처리를 할지 정의하는 RegistryFactory가 있다고 서두에 언급했습니다. RegistryFactory에 이번에 사용한 GlideUrl이 어떻게 처리할지에 대한 정보도 이미 정의되어 있어서, 별도 수정 없이 기존 Glide가 처리하는 방식 그대로 사용할 수 있습니다.
.append(GlideUrl.class, InputStream.class, new HttpGlideUrlLoader.Factory())
소스 출처 : https://github.com/bumptech/glide/blob/master/library/src/main/java/com/bumptech/glide/RegistryFactory.java#L354
만약, GlideUrl을 상속하지 않는다면 Model 처리가 불가능한 것으로 로그가 출력됩니다.
comments powered by Disqus
Subscribe to this blog via RSS.
LazyColumn/Row에서 동일한 Key를 사용하면 크래시가 발생하는 이유
Posted on 30 Nov 2024