본문 바로가기

Compose

[Compose] Compose 이해하기

Compose 공식 문서를 참고해 번역한 내용입니다.

 

Compose 이해

Compose는 선언형 UI 도구

  • 선언형 API를 제공하여 앱 UI를 쉽게 관리

 

선언형 프로그래밍 패러다임 (Declarative Programming Paradigm)

 

기존 Android View 계층 구조는 UI 위젯의 트리로 표시

  • findViewById 같은 함수를 사용해 트리를 탐색하고 메서드를 호출해 노드를 변경하는 방식

기존 방식의 문제점

  • 휴먼에러가 발생할 가능성이 크다

 

대안으로 선언형 UI 프로그래밍으로 전환

- 화면 전체를 개념적으로 재생성하고 필요한 변경사항만 적용하는 방식

- Compose는 선언형 UI Framework

 

Compose는

Data를 받아 Composable 함수들을 정의하여 UI 요소를 내보내 UI를 빌드할 수 있다

 

 

간단한 Composable 함수

(name이라는 String 데이터를 받아 Text UI를 내보낸다)

@Composable
fun Greeting(
    name: String,
    modifier: Modifier = Modifier
) {
    Text(
        text = "Hello $name!",
        modifier = modifier
    )
}

 

 

Composable의 특징

 

1. @Composable 주석으로 지정되어야 한다.

데이터를 UI로 변환하기 위한 함수라는 것을 컴파일러에게 알리는 역할

@MustBeDocumented
@Retention(AnnotationRetention.BINARY)
@Target(
    // function declarations
    // @Composable fun Foo() { ... }
    // lambda expressions
    // val foo = @Composable { ... }
    AnnotationTarget.FUNCTION,

    // type declarations
    // var foo: @Composable () -> Unit = { ... }
    // parameter types
    // foo: @Composable () -> Unit
    AnnotationTarget.TYPE,

    // composable types inside of type signatures
    // foo: (@Composable () -> Unit) -> Unit
    AnnotationTarget.TYPE_PARAMETER,

    // composable property getters and setters
    // val foo: Int @Composable get() { ... }
    // var bar: Int
    //   @Composable get() { ... }
    AnnotationTarget.PROPERTY_GETTER
)
annotation class Composable

 

2. 함수는 매개변수로 데이터를 받아 UI에 표시

 

3. 함수는 다른 Composable 함수를 호출할 수 있다

 

4. 함수는 아무것도 반환하지 않는다

 

5. 함수는 빠르고 멱등성의 성질을 가지며 side-effects(부작용)이 없다 (동일한 input은 동일한 output)

 

6. 동적일 수 있다 (Dynamic Contents)

@Composable
fun Greeting(
    name: String,
    modifier: Modifier = Modifier
) {
    if (name.isEmpty()) {
        Text(
            text = "Hello!",
            modifier = modifier
        )
    } else {
        Text(
            text = "Hello! $name",
            modifier = modifier
        ) 
    }
}

 

 

Recomposition (재구성)

기존 View 시스템에서는 setter를 호출하여 내부 상태를 변경하지만

Compose는 새로운 데이터를 사용해 Composable을 다시 호출한다 (재구성)

smart recomposition을 통해 변경된 컴포넌트만 재구성할 수 있다

 

예시) 버튼을 클릭하면 MainScreen의 clicks 데이터가 변해 새로운 clicks 데이터로 ClickCounter를 다시 호출

@Composable
fun MainScreen() {
    val clicks = remember { mutableIntStateOf(0) }
    ClickCounter(
        clicks = clicks.intValue,
        onClick = { clicks.intValue++ }
    )
}

@Composable
fun ClickCounter(
    clicks: Int,
    onClick: () -> Unit,
    modifier: Modifier = Modifier
) {
    Button(modifier = modifier, onClick = onClick) {
        Text("Clicked $clicks times")
    }
}

 

 

Composable은 잘못 사용하게 되면 재구성이 많은 빈도로 일어나게 되어 성능에 영향을 줄 수 있다

 

 

Compose를 사용할 때 아래와 같은 사항을 항상 생각해야 한다

 

1. Recomposition은 최대한 많은 수의 Composable 함수와 람다를 건너뛴다

Recomposition을 통해 일부 요소를 skip할 수 있다

@Composable
fun Greeting(
    firstName: String,
    lastName: String,
    modifier: Modifier = Modifier
) {
    Column(modifier = modifier) {
        // firstName 변경 시 recomposition, lastName만 변경 시 skip
        Text(
            text = "Hello! $firstName",
            modifier = modifier
        )
        Column {
            // lastName 변경 시 recomposition, firstName만 변경 시 skip
            Text(
                text = "Hello! $lastName",
                modifier = modifier
            )
        }
    }
}

 

 

2. Recomposition은 낙관적의며 취소될 수 있다

Compose는 매개변수가 다시 변경되기 전에 Recomposition을 완료할 것으로 예상

완료되기 전에 매개변수가 변경되면 Recomposition을 취소(UI 트리 삭제)하고 새 데이터를 사용해 다시 Recomposition 시작

 

3. Composable 함수는 애니메이션의 모든 프레임에서와 같은 빈도로 매우 자주 실행될 수 있다

자주 실행되면 앱 성능에 영향을 줄 수 있다.

만약 비용이 많이 드는 작업을 해야 한다면 Composable 외부로 이동하고 mutableStateOf 같은 함수를 사용해 데이터를 전달해야 한다

 

4. Composable 함수는 동시에 실행할 수 있다

현재는 동시에 실행할 수 없지만 Compose는 멀티스레드 지향적으로 설계되어 이런 방식으로 작성하는 것이 좋다

 

5. Composable 함수는 순서와 상관없이 실행할 수 있다

Composable 함수가 호출된 순서대로 실행된다고 가정할 수 있지만 반드시 그런 것은 아니다

Compose에는 우선순위가 높은 일부 UI 요소를 먼저 그릴 수 있는 옵션이 있다

 

'Compose' 카테고리의 다른 글

[Compose] Compose Phases  (0) 2025.02.09
[Compose] Composable 수명 주기  (0) 2025.02.09