Compose의 안정성

Compose는 유형을 안정적이거나 불안정한 것으로 간주합니다. 유형은 변경이 불가능하거나 Compose가 리컴포지션 간에 값이 변경되었는지 알 수 있는 경우 안정적입니다. Compose가 리컴포지션 간에 값이 변경되었는지 여부를 알 수 없는 경우 유형이 불안정합니다.

Compose는 컴포저블 매개변수의 안정성을 사용하여 리컴포지션 중에 컴포저블을 건너뛸 수 있는지 확인합니다.

  • 안정적인 매개변수: 컴포저블에 변경되지 않은 안정적인 매개변수가 있으면 Compose는 이를 건너뜁니다.
  • 불안정한 매개변수: 컴포저블에 불안정한 매개변수가 있는 경우 Compose는 구성요소의 상위 요소를 재구성할 때 항상 컴포저블을 재구성합니다.

앱에 Compose가 항상 재구성하는 불필요하게 불안정한 구성요소가 많이 포함되어 있으면 성능 문제 및 기타 문제가 발생할 수 있습니다.

이 문서에서는 앱의 안정성을 높여 성능과 전반적인 사용자 환경을 개선하는 방법을 자세히 설명합니다.

변경 불가능한 객체

다음 스니펫은 안정성 및 리컴포지션의 일반적인 원칙을 보여줍니다.

Contact 클래스는 변경 불가능한 데이터 클래스입니다. 이는 모든 매개변수가 val 키워드로 정의된 프리미티브이기 때문입니다. Contact 인스턴스를 만든 후에는 객체 속성 값을 변경할 수 없습니다. 그렇게 하려고 하면 새 객체를 만들게 됩니다.

data class Contact(val name: String, val number: String)

ContactRow 컴포저블에는 Contact 유형의 매개변수가 있습니다.

@Composable
fun ContactRow(contact: Contact, modifier: Modifier = Modifier) {
   var selected by remember { mutableStateOf(false) }

   Row(modifier) {
      ContactDetails(contact)
      ToggleButton(selected, onToggled = { selected = !selected })
   }
}

사용자가 전환 버튼을 클릭하고 selected 상태가 변경되면 어떻게 되는지 고려합니다.

  1. Compose는 ContactRow 내에서 코드를 재구성해야 하는지 평가합니다.
  2. ContactDetails의 유일한 인수가 Contact 유형임을 확인합니다.
  3. Contact는 변경할 수 없는 데이터 클래스이므로 Compose는 ContactDetails의 인수가 변경되지 않았음을 확인합니다.
  4. 따라서 Compose는 ContactDetails를 건너뛰고 재구성하지 않습니다.
  5. 반면에 ToggleButton의 인수가 변경되었으며 Compose는 이 구성요소를 재구성합니다.

변경 가능한 객체

이전 예에서는 변경할 수 없는 객체를 사용하지만 변경 가능한 객체를 만들 수도 있습니다. 다음 스니펫을 살펴보세요.

data class Contact(var name: String, var number: String)

이제 Contact의 각 매개변수가 var이므로 클래스는 더 이상 변경할 수 없습니다. 속성이 변경되면 Compose가 인식하지 못합니다. 이는 Compose가 Compose 상태 객체의 변경사항만 추적하기 때문입니다.

Compose는 이러한 클래스를 불안정하다고 간주합니다. Compose는 불안정한 클래스의 리컴포지션을 건너뛰지 않습니다. 따라서 Contact가 이러한 방식으로 정의되면 이전 예의 ContactRowselected가 변경될 때마다 재구성됩니다.

Compose에서 구현

Compose가 리컴포지션 중에 건너뛸 함수를 정확히 어떻게 결정하는지 생각해 보면 도움이 될 수 있지만 중요하지는 않습니다.

Compose 컴파일러가 코드에서 실행되면 각 함수와 유형을 여러 태그 중 하나로 표시합니다. 이러한 태그는 Compose가 리컴포지션 중에 함수나 유형을 처리하는 방식을 반영합니다.

함수

Compose는 함수를 skippable 또는 restartable로 표시할 수 있습니다. 함수를 다음 중 하나, 둘 다 또는 둘 다로 표시할 수 없습니다.

  • 건너뛸 수 있음: 컴파일러가 컴포저블을 건너뛸 수 있다고 표시하면 모든 인수가 이전 값과 같은 경우 Compose는 리컴포지션 중에 컴포저블을 건너뛸 수 있습니다.
  • 다시 시작 가능: 다시 시작할 수 있는 컴포저블은 리컴포지션을 시작할 수 있는 '범위' 역할을 합니다. 즉, 이 함수는 상태가 변경된 후 Compose가 리컴포지션을 위한 코드 재실행을 시작할 수 있는 진입점이 될 수 있습니다.

유형

Compose는 유형을 변경할 수 없거나 안정적인 것으로 표시합니다. 각 유형은 둘 중 하나입니다.

  • 변경 불가능: 속성 값을 변경할 수 없고 모든 메서드가 참조적으로 투명한 경우 Compose는 유형을 변경 불가능으로 표시합니다.
    • 모든 기본 유형은 변경 불가능으로 표시됩니다. 여기에는 String, Int, Float가 포함됩니다.
  • Stable: 생성 후 속성이 변경될 수 있는 유형을 나타냅니다. 런타임 중에 이러한 속성이 변경되면 Compose는 변경사항을 인식합니다.

디버그 안정성

앱에서 매개변수가 변경되지 않은 컴포저블을 재구성하는 경우 먼저 명확하게 변경 가능한 매개변수의 정의를 확인하세요. Compose는 개발자가 var 속성이 있는 유형 또는 불안정한 것으로 알려진 유형을 사용하는 val 속성을 전달하면 항상 구성요소를 재구성합니다.

Compose에서 안정성과 관련된 복잡한 문제를 진단하는 방법에 관한 자세한 내용은 디버그 안정성 가이드를 참고하세요.

안정성 문제 해결

Compose 구현의 안정성을 높이는 방법에 관한 자세한 내용은 안정성 문제 해결 가이드를 참고하세요.

요약

전반적으로 다음 사항에 유의해야 합니다.

  • 매개변수: Compose는 컴포저블의 각 매개변수 안정성을 판단하여 리컴포지션 중에 건너뛰어야 하는 컴포저블을 결정합니다.
  • 즉각적인 해결: 컴포저블을 건너뛰지 않고 성능 문제가 발생한 경우 먼저 var 매개변수와 같은 불안정성의 명확한 원인을 확인해야 합니다.
  • 컴파일러 보고서: 컴파일러 보고서를 사용하여 클래스에서 추론되는 안정성을 확인할 수 있습니다.
  • 컬렉션: Compose는 항상 컬렉션 클래스(예: List, SetMap)를 불안정한 것으로 간주합니다. 이것이 불변성을 보장할 수 없기 때문입니다. 대신 Kotlinx 변경 불가능한 컬렉션을 사용하거나 클래스에 @Immutable 또는 @Stable로 주석을 달 수 있습니다.
  • 기타 모듈: Compose는 Compose 컴파일러가 실행되지 않는 모듈의 경우 항상 불안정하다고 간주합니다. 필요한 경우 UI 모델 클래스에서 클래스를 래핑합니다.

추가 자료