
Kotlin Immutable, Stable 차이와 개념에 대해 학습한다.
Compose 동등성 비교
1. Compose의 Recomposition
코틀린은 2가지 유형의 동등성 비교가 있다.
- 구조적 동등성
- == 연산자를 사용해 두 객체의 값이 동일한지 비교한다.
- 내부적으로 equals() 메소드를 호출한다.
- 참조 동등성
- === 연산자를 사용해 두 객체의 메모리가 같은지 비교한다.
컴포즈는 코틀린 코드를 사용해 UI를 구성하기 때문에 두가지 동등성을 모두 사용하게 된다. 이때 적절하지 않은 동등성을 사용하게 된다면 불필요한 리컴포지션이 여러번 발생하고 성능에 큰 영향을 줄 수가 있다.
- @Immutable
- 컴포즈는 참조 동등성을 사용한다.
- 객체가 같다면 내용도 절대 변하지 않는다고 믿는다.
- @Stable
- 컴포즈는 구조적 동등성을 사용한다.
- 속성 값이 바뀌었는지 개별적으로 확인한다.
- Unstable 타입
- var, MutableList, mutableStateList 등의 커스텀 타입
- 무조건 변경된 것으로 처리해 리컴포지션 발생한다.
UI State는 @Immutable data class를 사용하는게 컴포즈 성능 최적화에 좋다.
2. 일반 클래스에서도 사용이 가능한데 data class에서 주로 사용하는 이유는 ?
코틀린에서 데이터를 담는 모델 클래스는 data class로 정의하는 것이 일반적이기 때문이다. copy(), equals(), hashCode()와 같이 기본적으로 제공해주는 메소드들이 있기 때문에 불변성을 유지하고 활용하기에 용이하다는 장점이 있기 때문이다.
3. Compose, @Immutable 컴파일과 런타임 관계
@Immutable을 사용하게 된다면 컴포즈 컴파일러가 불변성을 보장받고 이 정보를 바탕으로 런타임에 리컴포지션 최적화를 수행한다. @Immutable 객체가 파라미터로 전달된 컴포저블은 상위 컴포저블이 리컴포지션 되더라도 해당 객체가 변경되지 않았다면 리컴포지션을 건너뛰게 된다. 불필요하게 UI를 다시 그리는 작업이 줄어들기 때문에 성능 개선에 도움이 된다.
또, 멀티 모듈에서 모듈 간의 경계에 있는 데이터 클래스에 사용하게 된다면 컴포즈 컴파일러가 모듈 경계를 넘어도 해당 객체를 안정적으로 취급하게 된다. 때문에 멀티 모듈에서도 다른 모듈에 정의된 데이터 클래스를 사용해도 리컴포지션 최적화가 가능하다.
@Immutable, @Stable
1. @Immutable이란 ?
코틀린에서 불변이 약속된 클래스 인스턴스를 생성할때 사용한다. 불변이기에 val과 비슷하게 보일수도 있지만 val은 재할당을 막을뿐 참조하는 객체 자체가 내부적으로 mutable(ex. val list: ArrayList<T>) 할수도 있기 때문에 완벽한 불변을 보장하지 않지만 Immutable은 인스턴스가 생성된 이후 접근 가능한 모든 속성과 필드 변경이 불가능하다는 강력한 불변이다. 클래스에 @Immutable 어노테이션을 붙여 컴파일러에게 해당 클래스는 불변임을 명시적으로 알려주어 사용한다.
2. @Immutable이 왜 필요한가 ?
컴포즈 컴파일러는 안정적(Stable), 불안정적(Unstable)인지 data class에 대한 추론이 가능하다. 모든 구성이 val 속성이고 Int, String, Float 등 원시 타입으로만 이루어져있는 경우엔 @Immutable 어노테이션이 없어도 흡사하게 동작한다. 하지만, data class가 커스텀 타입 프로퍼티(다른 데이터 클래스 모델), List, Map 같은 코틀린 컬렉션 타입을 가지고 있다면 불안정적하다 추론하기 때문에 무조건 리컴포지션을 발생시킨다. 이런 이유로 컴포즈에게 명확하게 @Immutable을 붙여 불변하는 데이터 클래스라는걸 알려주는게 안전하다.
3. @Stable이란 ?
var 타입 프로퍼티를 가지고 있는 data class에 붙여 해당 클래스는 변경이 가능하다는걸 알려준다. val로 대부분 data class로 생성하기 때문에 불필요한 어노테이션이라고 생각이 들지만, MutableList 타입처럼 mutable한 데이터 타입일 경우 참조는 변하지 않지만 내부값은 변경된다. 이럴경우 컴포즈는 내부가 변경된걸 알 수가 없다. 때문에 @Stable 어노테이션을 붙여 변경될 경우 새객체를 만들어 변경한다는 용도이다.
결론
Compose + Orbit + MVI 구조에선 @Immutable로 구현하는게 적절하다. . .
'Android > Compose' 카테고리의 다른 글
| Navigation3 (0) | 2025.09.17 |
|---|---|
| [Compose] 상태관리 (0) | 2025.02.11 |