강력 건너뛰기 모드

강력한 건너뛰기는 Compose 컴파일러에서 사용할 수 있는 모드입니다. 사용 설정하면 다음 두 가지 방식으로 컴파일러의 동작이 변경됩니다.

  • 매개변수가 불안정한 컴포저블은 건너뛸 수 있음이 됩니다.
  • 불안정한 캡처가 있는 람다는 기억됩니다.

강력한 건너뛰기 모드 사용 설정

Gradle 모듈에 강력 건너뛰기를 사용 설정하려면 Gradle 구성의 composeCompiler 블록에 다음 옵션을 포함합니다.

composeCompiler {
   enableStrongSkipping = true
}

구성 가능한 건너뛰기 가능 여부

강력 건너뛰기 모드는 건너뛰기 및 구성 가능한 함수와 관련하여 Compose 컴파일러에서 일반적으로 적용하는 일부 안정성 규칙을 완화합니다. 기본적으로 Compose 컴파일러는 모든 인수에 안정적인 값이 있는 경우 구성 가능한 함수를 건너뛸 수 있는 함수로 표시합니다. 강력 건너뛰기 모드는 이러한 상황을 변경합니다.

강력한 건너뛰기를 사용 설정하면 다시 시작 가능한 모든 구성 가능한 함수를 건너뛸 수 있습니다. 이는 불안정한 매개변수가 있는지 여부와 관계없이 적용됩니다. 다시 시작할 수 없는 구성 가능한 함수는 건너뛸 수 없습니다.

건너뛰기 시점

리컴포지션 중에 컴포저블을 건너뛸지 결정하기 위해 Compose는 각 매개변수의 값을 이전 값과 비교합니다. 비교 유형은 매개변수의 안정성에 따라 다릅니다.

  • 불안정한 매개변수는 인스턴스 동등성 (===)을 사용하여 비교됩니다.
  • 안정적인 매개변수는 객체 동등 (Object.equals())을 사용하여 비교됩니다.

모든 매개변수가 이러한 요구사항을 충족하면 Compose는 리컴포지션 중에 컴포저블을 건너뜁니다.

컴포저블이 강력 건너뛰기를 선택 해제하는 것이 좋습니다. 즉, 다시 시작할 수 있지만 건너뛸 수 없는 컴포저블을 만드는 것이 좋습니다. 이러한 경우에는 @NonSkippableComposable 주석을 사용하세요.

@NonSkippableComposable
@Composable
fun MyNonSkippableComposable {}

클래스에 안정적인 주석 달기

인스턴스 동등성 대신 객체 동등성을 사용하는 객체를 원하는 경우에는 계속해서 지정된 클래스에 @Stable을 주석으로 추가합니다. 이 작업이 필요한 상황의 예로는 전체 객체 목록을 관찰할 때 Room과 같은 데이터 소스가 목록의 항목 중 하나가 변경될 때마다 목록의 모든 항목에 새 객체를 할당합니다.

람다 메모리

또한 강력 건너뛰기 모드는 컴포저블 내에서 람다를 더 많이 기억할 수 있게 합니다. 강력 건너뛰기를 사용 설정하면 구성 가능한 함수 내의 모든 람다가 자동으로 기억됩니다.

강력한 건너뛰기를 사용할 때 컴포저블 내에서 람다를 기억하기 위해 컴파일러는 remember 호출로 람다를 래핑합니다. 람다 캡처와 키가 연결됩니다.

다음 예와 같이 람다가 있다고 가정해 보겠습니다.

@Composable
fun MyComposable(unstableObject: Unstable, stableObject: Stable) {
    val lambda = {
        use(unstableObject)
        use(stableObject)
    }
}

강력한 건너뛰기를 사용 설정하면 컴파일러가 람다를 remember 호출로 래핑하여 메모합니다.

@Composable
fun MyComposable(unstableObject: Unstable, stableObject: Stable) {
    val lambda = remember(unstableObject, stableObject) {
        {
            use(unstableObject)
            use(stableObject)
        }
    }
}

키는 구성 가능한 함수와 동일한 비교 규칙을 따릅니다. 런타임은 인스턴스 동등성을 사용하여 불안정한 키를 비교합니다. 객체 동등성을 사용하여 안정적인 키를 비교합니다.

메모리화 및 리컴포지션

이러한 최적화로 인해 리컴포지션 중에 런타임이 건너뛰는 컴포저블의 수가 크게 증가합니다. 기억하지 않으면 런타임은 리컴포지션 중에 람다 매개변수를 사용하는 컴포저블에 새 람다를 할당할 가능성이 훨씬 높습니다. 따라서 새 람다는 마지막 컴포지션과 같지 않은 매개변수를 갖습니다. 이에 따라 재구성됩니다.

메모 방지

기억하지 않으려는 람다가 있다면 @DontMemoize 주석을 사용하세요.

val lambda = @DontMemoize {
    ...
}

APK 크기

컴파일할 때 건너뛸 수 있는 컴포저블은 건너뛸 수 없는 컴포저블보다 더 많은 코드를 생성합니다. 강력한 건너뛰기를 사용 설정하면 컴파일러는 거의 모든 컴포저블을 건너뛸 수 있는 것으로 표시하고 remember{...}에서 모든 람다를 래핑합니다. 따라서 강력한 건너뛰기 모드를 사용 설정해도 애플리케이션의 APK 크기에 미치는 영향은 매우 적습니다.

Now In Android에서 강력한 건너뛰기를 사용 설정한 후 APK 크기가 4KB 증가했습니다. 크기 차이는 주로 특정 앱에 있던 건너뛸 수 없는 컴포저블의 수에 따라 달라지지만 비교적 사소해야 합니다.