이미지를 위한 성능 최적화

이미지 작업을 할 때는 주의하지 않으면 금방 성능 문제가 발생할 수 있습니다. 큰 비트맵으로 작업할 때 OutOfMemoryError가 발생하기가 매우 쉽습니다. 앱이 최상의 성능을 발휘하게 만들려면 다음 권장사항을 따르세요.

필요한 크기의 비트맵만 로드하기

대부분의 스마트폰에는 큰 이미지 파일을 생성하는 고해상도 카메라가 있습니다. 화면에 이미지를 표시하는 경우 이미지 해상도를 낮추거나 이미지 컨테이너 크기까지만 이미지를 로드해야 합니다. 필요보다 더 큰 이미지를 지속적으로 로드하면 GPU 캐시가 소진되어 UI 렌더링 성능이 저하될 수 있습니다.

이미지 크기를 관리하려면 다음 안내를 따르세요.

  • 이미지 파일을 가능한 한 작게 축소합니다(출력 이미지에 영향을 주지 않음).
  • JPEG 또는 PNG 대신 WebP 형식으로 이미지를 변환합니다.
  • 다양한 화면 해상도에 맞는 더 작은 이미지를 제공합니다(도움말 #3 참고).
  • 이미지 로드 라이브러리를 사용하여 화면의 뷰 크기에 맞게 이미지를 축소합니다. 이렇게 하면 화면 로드 성능이 개선됩니다.

가능하면 비트맵 대신 벡터 사용하기

화면에 무언가를 시각적으로 표시할 때 벡터로 표현할 수 있는지 결정해야 합니다. 벡터 이미지는 다른 크기로 조정할 때 픽셀화되지 않으므로 비트맵보다 벡터 이미지를 사용하는 것이 좋습니다. 그러나 모든 것을 벡터로 표시할 수는 없습니다. 카메라로 촬영한 이미지는 벡터로 변환할 수 없습니다.

다양한 화면 크기에 맞는 대체 리소스 제공

앱과 함께 이미지를 제공하는 경우 기기 해상도에 따라 다양한 크기의 애셋을 제공하는 것이 좋습니다. 이렇게 하면 기기에서 앱의 다운로드 크기가 줄어들고 해상도가 낮은 기기에 더 낮은 해상도의 이미지가 로드되므로 성능이 개선됩니다. 다양한 기기 크기에 맞는 대체 비트맵을 제공하는 방법에 관한 자세한 내용은 대체 비트맵 문서를 확인하세요.

ImageBitmap을 사용할 때 그리기 전에 prepareToDraw 호출

ImageBitmap을 사용할 때 GPU에 텍스처를 업로드하는 프로세스를 시작하려면 실제로 그리기 전에 ImageBitmap#prepareToDraw()를 호출합니다. 그러면 GPU가 텍스처를 준비하고 화면에 시각 요소를 표시하는 성능을 향상할 수 있습니다. 대부분의 이미지 로드 라이브러리는 이러한 최적화를 이미 실행하지만 ImageBitmap 클래스를 직접 사용한다면 이 사항에 유의해야 합니다.

Painter 대신 Int DrawableRes 또는 URL을 컴포저블에 매개변수로 전달하는 것이 좋습니다.

이미지 처리의 복잡성으로 인해(예: Bitmaps의 equals 함수를 작성하는 데 드는 높은 계산 비용) Painter API는 안정적인 클래스로 명시하지 않습니다. 불안정한 클래스의 경우 데이터가 변경되었는지 컴파일러가 쉽게 추론할 수 없으므로 불필요한 리컴포지션으로 이어질 수 있습니다.

따라서 Painter를 매개변수로 전달하는 대신 URL 또는 드로어블 리소스 ID를 매개변수로서 컴포저블에 전달하는 것이 좋습니다.

// Prefer this:
@Composable
fun MyImage(url: String) {

}
// Over this:
@Composable
fun MyImage(painter: Painter) {

}

비트맵을 필요한 기간보다 오래 메모리에 저장하지 않기

메모리에 로드하는 비트맵이 많을수록 기기의 메모리가 부족할 가능성이 커집니다. 예를 들어 화면에 대량의 이미지 컴포저블 목록을 로드하는 경우 큰 목록을 스크롤할 때 메모리가 확보되도록 LazyColumn 또는 LazyRow를 사용합니다.

대용량 이미지를 AAB/APK 파일로 패키징하지 않기

앱 다운로드 크기가 커지는 주요 원인 중 하나는 AAB 또는 APK 파일 내에 패키징된 그래픽 때문입니다. APK Analyzer 도구를 사용하여 필요한 이미지 파일보다 크게 패키징하지 않도록 합니다. 크기를 줄이거나 이미지를 서버에 두고 필요할 때만 다운로드하는 것이 좋습니다.