Jetpack Compose에서 네트워크 이미지 로딩하기
Jetpack Compose에서 네트워크 이미지 로딩하기
Jetpack Compose에는 네트워크 URL로부터 이미지를 로딩하는 빌트인 API가 포함되어 있지 않습니다. 이는 의도적인 설계 결정으로, 네트워크 이미지 로딩에는 HTTP 요청, 비트맵 디코딩, 메모리 및 디스크 캐싱, 다운샘플링(downsampling), 생명주기 관리 등 다양한 복합적인 관심사가 수반되기 때문입니다. 서드파티 라이브러리는 이러한 관심사를 충분히 검증되고 최적화된 구현으로 처리합니다. Compose 환경에서 사용할 수 있는 대표적인 라이브러리로는 Coil, Glide, Landscapist 세 가지가 있으며, 각각 고유한 강점과 통합 방식을 갖추고 있습니다. 이번 면접 질문을 통하여 아래 내용들을 학습하실 수 있습니다.
- Compose가 네트워크 이미지 로딩을 빌트인으로 제공하지 않는 이유
- Coil, Glide, Landscapist의 통합 방식과 기능 비교
- Coil의
AsyncImage를 활용한 기본적인 네트워크 이미지 로딩 방법 - 네트워크 이미지 컴포넌트에서의 플레이스홀더(placeholder) 및 에러 처리 전략
빌트인 지원이 제공되지 않는 이유
네트워크에서 이미지를 로딩하려면 HTTP를 통한 데이터 다운로드, 대상 뷰 크기에 맞는 비트맵 디코딩, 디코딩된 비트맵의 메모리 및 디스크 캐싱, 메인 스레드를 차단하지 않는 동시 요청 처리, 그리고 이미지가 더 이상 표시되지 않을 때 리소스를 해제하는 작업이 필요합니다. 이러한 각각의 관심사에는 서로 다른 성능 트레이드오프를 가진 다양한 구현 전략이 존재합니다. Compose는 하나의 접근 방식을 프레임워크에 내장하는 대신, 독립적으로 발전할 수 있는 라이브러리에 이 역할을 위임하고 있습니다. 이러한 설계 철학 덕분에 개발자는 프로젝트의 요구사항에 가장 적합한 라이브러리를 자유롭게 선택하실 수 있습니다.
Coil
Coil은 Jetpack Compose 및 Kotlin Multiplatform과 네이티브하게 통합되는 코틀린 우선(Kotlin-first) 이미지 로딩 라이브러리입니다. 비동기 로딩에는 코루틴을, 네트워크 요청에는 OkHttp를 사용하며, 이 두 의존성은 대부분의 안드로이드 프로젝트에 이미 포함되어 있으므로 추가적인 의존성 크기를 최소화할 수 있습니다.
AsyncImage(
model = "https://example.com/image.jpg",
contentDescription = "Profile photo",
modifier = Modifier.size(120.dp),
placeholder = painterResource(R.drawable.placeholder),
error = painterResource(R.drawable.error)
)
AsyncImage는 전체 생명주기를 관리합니다. 컴포저블이 컴포지션에 진입하면 로딩을 시작하고, 로딩 중에는 플레이스홀더를 표시하며, 성공 시 결과 이미지를 보여주고, 실패 시에는 에러 드로어블을 표시합니다. 컴포저블이 컴포지션을 벗어나면 자동으로 요청을 취소하므로 리소스 누수를 방지할 수 있습니다.
Coil은 이미지 변환(transformation), 캐시 정책, 커스텀 헤더 등 고급 설정을 위한 ImageRequest도 제공합니다.
AsyncImage(
model = ImageRequest.Builder(LocalContext.current)
.data("https://example.com/image.jpg")
.crossfade(true)
.build(),
contentDescription = null
)