Jetpack Compose Doc 읽기 — Part1[기초]

hongbeom
hongbeomi dev
Published in
8 min readJun 10, 2021

Compose 공식 가이드 읽기(1/4)

목차

- 1부 Thinking in Compose
- 2부 Managing State
- 3부 Lifecycle
- 4부 Side-effects

What is compose?

Compose는 Android를 위한 현대적인 선언형 UI 도구 킷입니다. Compose는 xml을 사용하지 않고 앱 UI를 렌더링할 수 있게하는 선언형 API를 제공하며 더 쉽게 작성가능하고 유지관리할 수 있도록 지원해줍니다.

선언형 패러다임 전환

Compose의 선언형 접근 방식에서 위젯은 비교적 Stateless 상태이며 setter 또는 getter 함수를 노출하지 않습니다. 사실상 위젯은 객체로 노출되지 않습니다. 동일한 Composable 함수를 다른 인수로 호출하여 UI를 업데이트합니다. 이렇게 하면 앱 아키텍처 가이드에 설명된 대로 ViewModel과 같은 아키텍처 패턴에 상태를 쉽게 제공할 수 있습니다.

앱 로직은 최상위의 Composable 함수에 데이터를 제공합니다. 그럼 함수는 데이터를 사용하여 다른 Composable을 호출함으로써 UI를 형성하고 적절한 데이터를 아래로 전달합니다.

사용자가 UI와 상호작용하여 onClick과 같은 이벤트를 발생시키면 이런 이벤트를 앱 로직에 전달하여 앱의 상태를 변경해야 합니다. 상태가 변경되면 Composable 함수는 새 데이터와 함께 다시 호출됩니다. 이 프로세스를 Recomposing 이라고 합니다.

사용자가 UI 요소와 상호작용하며 이에 따라 이벤트가 트리거됩니다. 앱 로직이 이벤트에 응답합니다. 그러면 composable 함수가 필요한 경우 새로운 파라미터를 사용하여 자동으로 다시 호출됩니다.

Dynamic Content

이 함수는 이름 목록을 받아서 각 사용자에 대한 인사말을 생성합니다. if 문을 사용하여 특정 UI 요소를 표시할지 여부를 결정할 수 있으며 루프도 사용할 수 있습니다. 이렇게 기본 언어의 유연성을 완전히 활용할 수 있습니다. 이러한 성능과 유연성은 Jetpack Compose의 주요 이점 중 하나입니다.

Recomposing

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

예를 들어 다음과 같이 버튼을 표시하는 Composable 함수를 생각해 봅시다.

⚡️ Compose에서 프로그래밍할 때 알아야 할 몇 가지 사항이 있습니다.

  • Composable 함수는 순서와 관계없이 실행할 수 있습니다.
  • Composable 함수는 동시에 실행할 수 있습니다.
  • Recomposing은 최대한 많은 수의 Composable 함수 및 람다를 건너뜁니다.
  • Recomposing은 낙관적이며 취소될 수 있습니다.
  • Composable 함수는 애니메이션의 모든 프레임에서와 같은 빈도로 매우 자주 실행될 수 있습니다.

Composable 함수는 순서와 관계없이 실행할 수 있습니다.

Composable 함수의 코드를 살펴보면 코드가 표시된 순서대로 실행된다고 가정할 수 있습니다. 그러나 코드가 반드시 표시된 순서대로 실행되는 것은 아닙니다. Composable 함수에 다른 Composable 함수 호출이 포함되어 있다면 그 함수는 순서와 관계없이 실행될 수 있습니다. Compose에는 일부 UI 요소가 다른 UI 요소보다 우선순위가 높다는 것을 인식하고 그 요소를 먼저 그리는 옵션이 있습니다.

StartScreen, MiddleScreenEndScreen 호출은 순서와 관계없이 발생할 수 있습니다. 즉, 예를 들어 StartScreen()이 일부 전역 변수(side-effect)를 설정하고 MiddleScreen()이 이러한 변경사항을 활용하도록 할 수 없음을 의미합니다. 이러한 각각의 함수는 독립적이어야 합니다.

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

Compose는 Composable 함수를 동시에 실행하여 Recomposing을 최적화할 수 있습니다. 이를 통해 Compose는 다중 코어를 활용하고 화면에 없는 Composable 함수를 낮은 우선순위로 실행할 수 있습니다.

이 최적화는 Composable 함수가 백그라운드 스레드 풀 내에서 실행될 수 있음을 의미합니다. Composable 함수가 ViewModel에서 함수를 호출하면 Compose는 동시에 여러 스레드에서 이 함수를 호출할 수 있습니다.

애플리케이션이 올바르게 작동하도록 하려면 모든 Composable 함수에 side-effect가 없어야 합니다. 대신 UI 스레드에서 항상 실행되는 onClick과 같은 콜백에서 side-effect를 트리거합니다.

Composable 함수가 호출될 때 호출자와 다른 스레드에서 호출이 발생할 수 있습니다. 즉, Composable 람다의 변수를 수정하는 코드는 피해야 합니다. 이러한 코드는 스레드로부터 안전하지 않을 뿐만 아니라 Composable 람다가 허용하지 않는 side-effect가 존재하기 때문입니다.

다음은 목록과 개수를 표시하는 컴포저블을 보여주는 예입니다.

이 코드는 side-effect가 없으며 매개변수로 받은 리스트를 UI로 변환합니다. 이 코드는 작은 리스트를 표시할 때 유용한 코드입니다. 그러나 함수가 로컬 변수를 쓰는 경우 이 코드는 스레드로부터 안전하지 않거나 적절하지 않습니다.

이 예에서 items는 모든 Recomposing을 통해 수정됩니다. 수정은 애니메이션의 모든 프레임에서 또는 목록이 업데이트될 때 실행될 수 있습니다. 어느 쪽이든 UI에 잘못된 개수가 표시됩니다. 이 때문에 이런 방식은 Compose에서 지원되지 않습니다.

Recomposing은 가능한 한 많이 건너뜁니다.

UI의 일부가 잘못된 경우 Compose는 업데이트해야 하는 부분만 Recomposing하기 위해 최선을 다합니다. 즉, UI 트리에서 위 또는 아래에 있는 Composable을 실행하지 않고 단일 버튼의 Composable을 다시 실행하는 것을 건너뛸 수 있습니다.

이러한 각 범위는 Recomposing 도중에 실행되는 유일한 부분일 수 있습니다. Compose는 header가 변경될 때 상위 요소 중 어느 것도 실행하지 않고 Column 람다로 건너뛸 수 있습니다. 그리고 Column을 실행할 때 Compose는 names가 변경되지 않았다면 LazyColumnItems를 건너뛰도록 선택할 수 있습니다.

다시 말하지만, 모든 구성 가능한 함수 또는 람다를 실행하는 작업에는 side-effect가 없어야 합니다. side-effect를 가져가야 할 때는 콜백에서 side-effect를 트리거해야 합니다.

Recomposing은 낙관적입니다.

Compose가 Composable의 매개변수가 변경되었을 수 있다고 생각할 때마다 Recomposing이 시작됩니다. Recomposing은 낙관적입니다. 즉, Compose는 매개변수가 다시 변경되기 전에 Recomposing을 완료할 것으로 예상합니다. Recomposing이 완료되기 전에 매개변수가 변경되면 Compose는 Recomposing을 취소하고 새 매개변수를 사용하여 Recomposing을 다시 시작할 수 있습니다.

Recomposing이 취소되면 Compose는 Recomposing에서 UI 트리를 삭제합니다. 표시되는 UI에 종속되는 side-effect가 있다면 composing이 취소된 경우에도 side-effect가 적용됩니다. 이로 인해 일관되지 않은 앱 상태가 발생할 수 있습니다.

낙관적인 Recomposing을 처리할 수 있도록 모든 Composble 함수 및 람다가 멱등원이고 side-effect가 없는지 확인해야 합니다.

Composable 함수는 매우 자주 실행될 수 있음

경우에 따라 Composable 함수는 UI 애니메이션의 모든 프레임에서 실행될 수 있습니다. 함수가 기기 저장소에서 읽기와 같이 비용이 많이 드는 작업을 실행하면 이 함수로 인해 UI 버벅거림이 발생할 수 있습니다.

예를 들어 위젯이 기기 설정을 읽으려고 하면 잠재적으로 이 설정을 초당 수백 번 읽을 수 있으며 이는 앱 성능에 치명적인 영향을 줄 수 있습니다.

Composable 함수에 데이터가 필요하다면 데이터의 매개변수를 정의해야 합니다. 그런 다음, 비용이 많이 드는 작업을 구성 외부의 다른 스레드로 이동하고 mutableStateOf 또는 LiveData를 사용하여 Compose에 데이터를 전달할 수 있습니다.

2부 Managing State로 이어서 작성하겠습니다.

읽어주셔서 감사합니다🙌

--

--