Compose 이해하기(1)

햄햄·2022년 5월 27일
0

Compose

목록 보기
1/7
post-thumbnail

Jetpack Compose는 Android를 위한 현대적인 선언형 UI 도구 키트입니다. Compose는 앱 UI를 렌더링할 수 있게 하는 선언형 API를 제공하여 앱 UI를 더 쉽게 작성하고 유지관리할 수 있도록 지원합니다.

선언형 프로그래밍 패러다임

지금까지 Android 뷰 계층 구조는 UI 위젯의 트리로 표시할 수 있었습니다. 새로운 데이터를 표시하기 위해서는 UI 계층 구조를 업데이트해야 합니다.
UI를 업데이트하는 가장 일반적인 방법은 findViewById()와 같은 함수를 사용하여 트리를 탐색하고 button.setText(String), container.addChild(View)와 같은 메서드를 호출하여 노드를 변경하는 것입니다. 이러한 메서드는 위젯의 내부 상태를 변경합니다.

뷰를 수동으로 조작하면 오류가 발생할 가능성이 커집니다. 데이터를 여러 위치에서 렌더링한다면 데이터를 표시하는 뷰 중 하나를 업데이트하는 것을 잊기 쉽습니다.

Compose는 화면 전체를 개념적으로 재생성한 후 필요한 변경사항만 적용하는 방식으로 작동합니다. 이러한 접근 방식은 Stateful 뷰 계층 구조를 수동으로 업데이트할 때의 복잡성을 방지할 수 있습니다.

Stateful?
findViewById<TextView>(R.id.text).text = "안녕하세요"
위 코드는 id가 text인 TextView의 text 프로퍼티에 "안녕하세요"라는 state를 저장합니다. 따라서 state를 가지고 있기에 Stateful하다고 할 수 있습니다.

간단한 composable 함수를 살펴보자

Compose를 사용하면 데이터를 받아서 UI 요소를 내보내는 composable 함수를 정의하여 UI를 빌드할 수 있습니다.

위는 String을 받아서 인사말 메시지를 표시하는 Text 위젯을 내보내는 간단한 composable 함수입니다. 위 함수에 관한 몇가지 특징은 아래와 같습니다.

  • @Composable 주석은 이 함수가 데이터를 UI로 변환하기 위한 함수라는 것을 Compose 컴파일러에 알립니다
  • composable 함수는 매개변수를 받을 수 있으며, 이 매개변수를 통해 앱 로직이 UI를 형성할 수 있습니다
  • composable 함수는 다른 composable 함수(ex Text())를 호출하여 UI 계층 구조를 내보냅니다.
  • 원하는 화면 상태를 설명하므로 아무것도 반환할 필요가 없습니다
  • 함수는 빠르고 side-effect가 없습니다.

    side-effect가 없다는 의미?

    • 동일한 매개변수로 여러 번 호출될 때 언제나 동일한 방식으로 작동하며, 전역 변수 또는 random()과 같은 값을 사용하지 않습니다.
    • 함수는 프로퍼티 또는 전역 변수 수정을 하지 않고 UI를 형성합니다.

선언형 패러다임으로의 전환!

기존에는 명령형 UI 도구 키트를 사용해 위젯의 트리를 인스턴스화함으로써 UI를 초기화합니다.(ex XML 레이아웃 파일을 inflate) 각 위젯은 자체의 내부 state를 유지하고 상호작용할 수 있는 getter 및 setter 메서드를 노출합니다.
Compose의 선언형 접근 방식에서 위젯은 비교적 Stateless 상태이며 setter 또는 getter를 노출하지 않습니다. 사실상 위젯은 객체로 노출되지 않습니다.

비교적 Stateless라는건?
remember를 사용하여 객체를 저장하는 composable은 내부 상태를 생성하기에 Stateful composable입니다.


앱 로직은 최상위 composable 함수에게 데이터를 제공합니다. 그러면 함수는 데이터를 사용해 다른 composable 함수를 호출함으로 UI를 형성하고 데이터를 아래의 계층 구조로 전달합니다.

사용자가 UI와 상호작용 할 때 UI는 onClick과 같은 이벤트를 발생시킵니다. 이벤트를 통해 앱의 상태가 변경되면 composable 함수는 새 데이터와 함께 다시 호출됩니다. 이렇게 하면 UI 요소가 다시 그려집니다. 이 프로세스를 recomposition라고 합니다.

동적 콘텐츠

composable 함수는 XML이 아닌 Kotlin으로 작성되기 때문에 동적입니다.

@Composable
fun Greeting(names: List<String>) {
    for (name in names) {
        Text("Hello $name")
    }
}

이 함수는 이름 목록을 받아서 각 사용자에 대한 인사말을 생성합니다. 특정 UI 요소를 표시할지 여부를 결정할 수 있고, 루프나 도우미 함수를 호출할 수 있습니다.
이러한 성능과 유연성은 Jetpack Compose의 주요 이점 중 하나입니다.

Recomposition

명령형으로 UI를 변경하기 위해서는 위젯에서 setter을 호출하여 내부 state를 변경했습니다. Compose에서는 새로운 데이터를 사용해 composable 함수를 다시 호출합니다. 이렇게 하면 함수가 recomposition되며, 필요한 경우 함수에서 내보낸 위젯이 새 데이터로 다시 그려집니다. Compose 프레임워크는 변경된 구성요소만 지능적으로 recomposition할 수 있습니다.

Compose는 새 입력을 기반으로 재구성할 때 변경되었을 수 있는 함수 또는 람다만 호출하고 나머지는 건너뜁니다. 매개변수가 변경되지 않은 함수 또는 람다를 모두 건너뜀으로써 Compose의 재구성이 효율적으로 이루어질 수 있습니다.

함수의 recomposition는 건너뛸 수 있으므로 composable 함수는 side-effect에 의존해서는 안됩니다. 예를 들어 위험한 side-effect의 예로는 다음이 있습니다.

  • 공유 객체의 프로퍼티 쓰기
  • ViewModel의 observable 업데이트
  • 쉐어드 프리퍼런스 업데이트
    composable 함수는 빨라야합니다. 따라서 비용이 많이 드는 작업을 실행할 경우 백그라운드 코루틴에서 작업을 실행하고 결과를 composable 함수의 매개변수로 전달해야합니다.

https://developer.android.com/jetpack/compose/mental-model

0개의 댓글