Android/Jetpack Compose

Jetpack Compose : Strong Skipping Mode

chattymin 2024. 4. 25. 15:58
728x90
반응형
주의 사항 : Strong Skipping Mode는 현재 실험적이고 아직 프로덕션 용도로 사용될 준비가되지 않았습니다. Compose 1.7에서 활성화 하는 것을 목표로 하고있습니다

 

Strong Skipping Mode

Compose Compiler 1.5.4 version에 추가된 실험적인 모드입니다.

Strong Skipping Mode를 적용시킨다면 아래와 같은 두가지 방법으로 동작을 변경시킵니다.

- 불안정한 매개변수가 있는 컴포저블을 안정화(skippable)하게 변경합니다.

- 불안정한 Lambda는 remember를 적용시킵니다.

skippable : 컴파일러가 컴포저블을 건너뛸 수 있음. 리컴포지션이 되지 않음

 

 

Composable skippability

기본적으로 Compose 컴파일러는 Composable Function의 arguments들이 안정적이라면 skippable 하다고 표시합니다.

Strong Skipping Mode가 skippable 할 수 있도록 돕습니다.

 

Strong Skipping Mode가 활성화 되어있다면, 불안정한 arguments들이 있든 없든, 모든 restartable한 Composable Function들은 skippable한 것으로 표시해버립니다. restartable하지 않은 Composable Function은 unskippable한 상태로 유지합니다.

 

Recomposition 과정에서 해당 값의 Recompositon 여부를 결정하기 위해 자신의 이전 값과 instance equality를 사용하여 비교를 진행합니다. 안정적인 값의 경우 Object.equals()를 사용하여 이전 값과 비교합니다.

 

모든 매개변수가 이러한 요구 사항을 충족하면 Recomposition 중에 해당 composable을 skip 합니다.

composable 함수를 Strong Skipping에서 제외하려면(즉, 재시작이 가능하지만 스킵하지 않는 composable이 필요한 경우) @NonSkippableComposable 주석을 사용할 수 있습니다.

@NonSkippableComposable
@Composable
fun MyNonSkippableComposable {}

 

 

여전히 @Stable 주석을 Class에 추가해야 하나요?

Object Equality 대신 Instance Equality을 사용하여 개체를 비교하려면 여전히 클래스에 @Stable 주석을 추가해야 합니다.

 

Object Equalty
- 두 객체가 같은 객체를 참조하는지 여부 확인
- 즉, 메모리상에 동일한 위치에 있는지 비교
Instance Equality
- 두 객체가 동일한 내용을 가지고 있는지 여부 확인
- 즉, 객체의 내용이 같은지 비교

 

 

 

 

Lambda memoization

Strong Skipping Mode를 사용한다면 Composable 함수 내부의 Lambda에 대해서 더욱 강력한 memoization을 활성화 합니다.

기본적으로 Compose Compiler는 안정적인 값을 가지고 있는 컴포저블 함수에서 Lambda를 memoize 합니다. 추가적으로 Composable Lambda는 항상 mamoized됩니다.

참고 : 람다는 항상 memoize되지만 kotlin compiler에서 되는 것이지 Compose compiler에서 되는 것이 아닙니다!

 

만약 Strong Skipping을 적용한다면 불안정한 값을 가진 람다도 memoize됩니다.

Lambda를 remember로 wrapping하여 memoize 합니다

// 기존 코드
@Composable
fun MyComposable(unstableObject: Unstable, stableObject: Stable) {
    val lambda = {
        use(unstableObject)
        use(stableObject)
    }
}

위와 같은 코드가 Strong Skipping이 적용된다면 아래와 같이 remember로 wrappging됩니다.

// Strong Skipping 적용 후
@Composable
fun MyComposable(unstableObject: Unstable, stableObject: Stable) {
    val lambda = remember(unstableObject, stableObject) {
        {
            use(unstableObject)
            use(stableObject)
        }
    }
}

remember의 key값들은 composable 함수와 동일한 비교 규칙을 가지게 됩니다.

unstable한 key는 Instance Equality를 통해, stable한 key는 Object Equality를 통해 비교 됩니다.

일반적인 remember와는 차이가 있습니다!
remember에서는 모든 key가 Object Equality를 통해 비교됩니다

 

 

이 과정이 수행된다면 recompositon시 skip할 수 있는 composable의 수가 크게 줄어들게 됩니다. 

만약 remember로 wrapping해두지 않는다면 lambda를 가지고있는 모든 composable은 recompositon시 lambda가 새로 할당되게 됩니다.

일반적으로 사람들이 많이 하는 오해는 "unstable한 key를 가진 lambda는 unstable하다" 라는 것입니다.
하지만, lambda는 항상 stable합니다.
다만, memoize되지 않기 때문에 recompositon시 재할당 되어 skip이 불가능 합니다.

 

만약 lambda가 memoize되지 않길 원한다면 @DontMemoize 어노테이션을 붙이면 됩니다.

val lambda = @DontMemoize {
    ...
}

 

 

Strong Skipping Mode를 적용하는 방법

gradle module에 적용시키면 됩니다.

tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>() {
    compilerOptions.freeCompilerArgs.addAll(
        "-P",
        "plugin:androidx.compose.compiler.plugins.kotlin:experimentalStrongSkipping=true",
    )
}

 

 

모든 내용은 googlesource문서를 기반으로 작성되었습니다

728x90
반응형