프로그래밍/Android

[Jetpack Compose] @Immutable과 @Stable이란

Lou Park 2023. 12. 25. 17:09

Stable과 Unstable

Recomposition이 일어날때, Compose는 Stable과 Unstable로 유형을 구분한다.

Stable: 불변하는 것(Immutable), 혹은 Recomposition간에 값이 변경되었는지 여부를 추적할 수 있는 경우.
Unstable: Recomposition간에 값이 변경되었는지 알 수 없는 경우.

 

만약에 어떤 타입이 Stable하다면 Skip할 수 있지만 Unstable하다면 다시 그려야하므로, Stable과 Unstable하다는 것은 Compose에게 아주 중요하고 이것은 결국 성능에까지도 영향을 미치게 된다.

 

따라서 가능한한 클래스를 Immtable하게 만든다면 성능에 조금이나마 도움이 될 것이다.

 

@Immutable

@Immutable은 컴포즈 컴파일러에게 이 객체는 불변한다고 말해주는 어노테이션이다. 값을 바꾸기보다 copy나 새로운 객체를 생성함으로서 새로운 불변하는 객체로 대체한다. 모든 원시타입들(String, Int, Float...)은 Immutable로 간주된다.

 

@Immutable 언제 사용할까?

UiState를 만들때 List를 포함하는 것은 일반적이다.

data class SomeViewState {
    val list: List<String>
}

List의 인터페이스를 보면 Immutable하다고 생각할 수 있다.

하지만...!

SomeViewState(mutableListOf())

사실 이렇게도 쓸 수 있다!

변수는 상수라고하더라도 그 구현은 여전히 Mutable하다.

이러한 이유로 컴포즈 컴파일러는 Collection들을 모두 Unstable로 취급한다. 그게 List건, MutableList건간에 말이다.

이 경우 2가지 방법이있는데, 첫번째가 바로 @Immutable 어노테이션을 달아주는 것이다.

@Immutable
data class SomeViewState {
    val list: List<String>
}

혹은 Kotlinx Immutable Collection의 ImmutableList로 바꾸어주면된다.

@Immutable
data class SomeViewState {
    val list: ImmutableList<String>
}

 

@Stable

@Stable은 컴포즈 컴파일러에게 이 객체는 변할 수 있지만, 변한다면 컴포즈 런타임이 알 수 있다는 것을 말하는 어노테이션이다.

 

@Stable은 언제 사용할까?

컴포즈 런타임이 알 수 있다? @Stable의 설명이 아리까리할 수 있다. 하지만 아래 예시코드를 보자.

@Stable
class MyStateHolder {
  var isLoading by mutableStateOf(false)
}

 

그렇다. MutableState!

Snapshot 시스템의 도움으로 컴포즈 런타임은 MutableState가 변한다면 통지받을 수 있다.

이렇게 클래스를 만들때 var 필드가 속해있긴하지만 MutableState등으로 관리가 된다면 @Stable 어노테이션을 달아줄 수 있다.

 


 

 

다시 Stable의 정의를 살펴보면 Compose에서 Stable한 객체는 @Immutable 혹은 @Stable을 포함한다는 것을 알 수 있다.

Stable: 불변하는 것(Immutable), 혹은 Recomposition간에 값이 변경되었는지 여부를 추적할 수 있는 경우.