고화질 사진을 많이 띄워야 하는 프로젝트가 있었다. Glide 는 한번 로딩했던 사진을 알아서 캐싱 처리해주는 좋은 라이브러리지만, 최초 진입시엔 캐싱처리가 되지 않은 상태이기 때문에 로딩이 느릴 수밖에 없었다.
그러다보니 서버단이 아닌 앱단에서 조금이라도 로딩 속도를 개선해 사용자 경험을 개선할 수 있는 방법이 있으면 좋겠다고 생각했다.
다행히 구글링 해보니 Glide 자체 기능에 preload 라는게 있었다. 간단하게 설명하자면 recyclerView가 스크롤 되기 전에 사진을 미리 로드하는건데, 적용은 해당 블로그를 참고했다.
Glide 로 이미지 로드하는 코드는 여러 파일에서 사용하기에 확장 함수로 만들어줬다. 원래는 아래 setImage 함수를 사용해서 띄우고 있었고, 이번에 preload 함수를 추가해줬다.
package com.example.presentation.util.ext
import android.content.Context
import android.widget.ImageView
import com.bumptech.glide.Glide
fun ImageView.setImage(imageView: ImageView, url: String?) {
Glide.with(this).load(url)
.into(imageView)
}
fun Context.preloadImage(url: String?) {
if (url.isNullOrEmpty()) return
Glide.with(this)
.load(url)
.preload()
}
recyclerView 의 어댑터에서 호출
recyclerView는 화면에 보이는 아이템만 그리기 때문에, 스크롤 중에 곧 화면에 나타날 아이템의 이미지를 미리 로드해 조금 빠르게 띄우는 것. 이 과정에서 인덱스를 기반으로 현재 아이템 주변의 이미지 URL을 가져와야 하므로, position 값이 필요하다.
class ResultViewAdapter(
private val onClickStudio: (String, String) -> Unit
) : ListAdapter<StudioInfoWithConcept, ResultViewHolder>(StudioDiffCallback) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ResultViewHolder {
return ResultViewHolder(
ItemResultViewBinding.inflate(LayoutInflater.from(parent.context), parent, false),
onClickStudio
)
}
override fun onBindViewHolder(holder: ResultViewHolder, position: Int) {
val studio = getItem(position)
val context: Context = holder.itemView.context
setImagePreload(context, position)
holder.bind(studio)
}
override fun getItemCount(): Int {
return currentList.size
}
companion object {
private val StudioDiffCallback = object : DiffUtil.ItemCallback<StudioInfoWithConcept>() {
override fun areItemsTheSame(
oldItem: StudioInfoWithConcept,
newItem: StudioInfoWithConcept
): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(
oldItem: StudioInfoWithConcept,
newItem: StudioInfoWithConcept
): Boolean {
return oldItem == newItem
}
}
}
// 현재 인덱스 기준으로 preload
private fun setImagePreload(context: Context, position: Int) {
if (position < currentList.size - 1) {
context.preloadImage(currentList[position + 1].profileURL)
}
if (position > 0) {
context.preloadImage(currentList[position - 1].profileURL)
}
}
}
preload 유무 차이를 비교하기 위해 캐시 삭제 및 에뮬레이터 wipe data 하고 재시도해봤다. 확실히 기존보다 조금 더 빠르게 띄워졌다!
한번 이미지를 띄운 이후에는 글라이드가 알아서 캐시처리를 해주기 때문에 사진이 빨리 띄워지지만, 초기 로딩속도를 조금이나마 개선하는 것이 목적이라면 이렇게 preload 를 적용하는게 좋을 것 같다.
적용 전

적용 후

잘 활용하지 않았던 기능을 적용해 새로운 최적화를 시도해보는 것은 값진 경험이었다. 라이브러리를 너무 관성적으로 사용하지 않았나- 하는 생각이 들어 반성하는 계기가 되었다.
Glide.with(this)
.load(R.drawable.imgfile)
.placeholder(R.drawable.img_place_holder)
.error(R.drawable.img_error)
.fallback(R.drawable.no_img)
.into(imageView)