Compose UI Performance와 Stability: 실무 가이드
Android Compose를 사용하여 성능과 안정성을 확보하는 것은 사용자 경험을 개선하고 유지보수를 용이하게 하는 데 필수적입니다. 이 글에서는 Android 개발자 문서의 Compose Stability를 바탕으로, 주요 개념과 실전 예제를 자세히 살펴봅니다.
1. 기본 개념: Compose Stability란?
Compose Stability는 Compose UI에서 불필요한 재구성을 줄여 성능을 최적화하고, UI의 상태를 예측 가능하게 유지하는 것을 의미합니다. 핵심은 다음과 같습니다:
- Stable Object: 안정적인 객체로, 동일한 입력에 대해 동일한 결과를 제공합니다.
- Immutable Object: 불변 객체로, 객체의 내부 상태가 변경되지 않음을 보장합니다.
- Remember: Compose에서 상태를 효율적으로 유지하는 도구입니다.
2. 안정적인 매개변수와 불안정한 매개변수
Compose에서 매개변수는 안정적인지 여부에 따라 UI 재구성에 영향을 미칩니다. 안정적인 매개변수는 불필요한 재구성을 방지하지만, 불안정한 매개변수는 재구성을 트리거할 수 있습니다.
안정적인 매개변수의 조건:
@Stable
어노테이션이 적용된 객체.- Kotlin의 불변 객체 (Immutable objects).
- Compose의 상태 관리 API (
remember
,mutableStateOf
등)를 활용해 안정성을 보장한 객체.
불안정한 매개변수의 조건:
- 매번 새로운 인스턴스를 생성하는 객체.
- 변경 가능한 컬렉션 (mutable collections).
- 안정성 보장이 없는 람다 함수.
예제: 안정적인 매개변수와 불안정한 매개변수 비교
@Composable
fun Greeting(stableName: String, unstableName: () -> String) {
Text("Hello, $stableName!") // 안정적인 매개변수
Text("Hello, ${unstableName()}!") // 불안정한 매개변수
}
@Composable
fun Parent() {
val stableName = "Compose"
val unstableName = { "Compose at ${System.currentTimeMillis()}" }
Greeting(stableName = stableName, unstableName = unstableName)
}
위 예제에서 stableName
은 안정적이지만, unstableName
은 매번 다른 값을 반환할 수 있으므로 Compose가 불필요한 재구성을 트리거할 수 있습니다.
Compose UI Performance와 Stability: 실무 가이드 (Part 2)
markdown
복사
3. 불필요한 재구성을 방지하는 기술들
Compose에서 불필요한 재구성을 줄이기 위해 사용할 수 있는 다양한 기법이 있습니다. 이를 활용하면 UI 성능 최적화에 큰 도움을 줄 수 있습니다.
1. val
사용하기
val
키워드는 값을 재할당하지 않도록 보장하기 때문에 안정적인 상태를 유지하는 데 유리합니다.
@Composable
fun Example() {
val name = "Compose"
Text(name) // 안정적
}
var
대신 val
을 사용하면 변경 가능성을 줄이고 재구성 트리거를 최소화할 수 있습니다.
2. remember
로 상태 유지
remember
를 사용하여 컴포저블이 재구성되더라도 상태를 유지할 수 있습니다.
@Composable
fun Counter() {
val count = remember { mutableStateOf(0) }
Button(onClick = { count.value++ }) {
Text("Count: ${count.value}")
}
}
3. 안정적인 컬렉션 사용
Mutable 컬렉션 대신 Immutable 컬렉션을 사용하는 것이 좋습니다.
val items = listOf("Apple", "Banana", "Cherry") // Immutable
LazyColumn {
items(items) { item ->
Text(item)
}
}
4. derivedStateOf
사용
파생된 상태를 계산할 때 derivedStateOf
를 사용하여 필요한 경우에만 재구성을 트리거합니다.
@Composable
fun GreetingWithMessage(name: String) {
val message by remember(name) {
derivedStateOf { "Hello, $name!" }
}
Text(message)
}
5. 람다 함수 안정화
람다 함수는 기본적으로 불안정하지만, remember
를 사용하여 안정성을 보장할 수 있습니다.
@Composable
fun Parent() {
val onClick = remember {
{ println("Button clicked") }
}
Button(onClick = onClick) {
Text("Click me")
}
}
6. key
를 명확히 지정
LazyColumn
과 같은 리스트에서 key
를 명시적으로 지정하여 항목 재구성을 방지합니다.
@Composable
fun NameList(names: List<String>) {
LazyColumn {
items(names, key = { it }) { name ->
Text("Name: $name")
}
}
}
4. Compose가 다시 그려지는 경우와 방지 방법
Compose는 입력이 변경되었거나 상태가 변한 경우에만 해당 UI를 다시 그립니다. 그러나 불필요한 재구성을 방지하려면 위의 기법들을 적극적으로 활용해야 합니다.
5. Compose Stability 확인 도구 활용
Android Studio의 Stability Inspector를 사용하면 해당 리컴포지션되는 경우들을 확인할 수 있으니 한번 해보시길 바랍니다.
방법은
- Build > Analyze Compose 메뉴 선택하고
- Stability 관련 경고 및 불필요한 재구성 문제를 확인하면 됩니다.
결론
Compose에서 성능 최적화를 위해서는 안정적인 매개변수를 유지하고, 상태 관리와 API를 적절히 활용해야 합니다. 불필요한 재구성을 막고 효율적인 UI를 설계하여 사용자 경험을 최적화를 고려해보세요.
공시문서링크
https://developer.android.com/develop/ui/compose/performance/stability?hl=ko
'코틀린' 카테고리의 다른 글
Sealed Class와 Enum Class의 차이점 (0) | 2025.01.15 |
---|---|
코틀린 제네릭이란? (in, out) (1) | 2025.01.14 |
불변 객체 (0) | 2022.12.14 |
inline 함수 (0) | 2022.08.31 |
코틀린 by란? (0) | 2022.06.28 |