본문 바로가기
flutter/How Flutter Works

#2 The Three Trees (세 가지 트리 구조)

by ch5c 2026. 1. 17.
반응형

 

https://ch5c.tistory.com/147

 

 

[한국어 번역] How Flutter Works: The Three Trees #DecodingFlutter (2/6)

https://www.youtube.com/watch?v=xiW3ahr4CRU.인트로 (Intro)0:00CRAIG LABENZ:“How Flutter Works” 에피소드 2에 다시 오신 것을 환영합니다.0:10이전 에피소드에서 저는 Flutter가 주로 세 가지 서로 다른 트리 구조에

ch5c.tistory.com

위젯이란 무엇인가

플러터는 선언형 API를 제공하는데 각각의 위젯은 불변(immutable)이며 일회용(disposable) 임.

즉, UI의 해당 부분이 변경될 필요가 있을 때마다 위젯은 버려지고 새로 생성되게 된다는 것인데 이러한 일회용 위젯은 애플리케이션 코드를 단순화해 주며 빠르게 작동해주게 한다고 함.

선언형 API란?
"무엇을 하고 싶은지를 선언하면, 그걸 어떻게 실행할지는 API가 알아서 처리"
플러터에서 사용하는 위젯을 떠올려 보면 됨.
  • 절차를 설명하지 않고 목적을 설명
  • 사용자는 내부 동작 방식(로직, 절차 등)을 신경 쓰지 않고, 결과나 상태만 명시

위젯은 크게 세 가지 유형으로 나뉘는데 아래와 같음.

  • StatelessWidget (상태를 유지하지 않는 위젯)
  • StatefulWidget (상태를 유지하는 위젯)
  • RenderObjectWidget (렌더링 객체 위젯)

여기서 대부분은 StatelessWidget 또는 StatefulWidget을 상속하여 사용하게 되는데 그 결과로 RenderObject는 나중에 다룰 비교적 특수한 경우로 남게 됨.

또한 네 번째 유형의 위젯인 InheritedWidget(상속 위젯)도 있는데 이 위젯은 데이터를 전달하기만 하고 자체적으로는 아무것도 렌더링 하지 않음.

StatelessWidget과 StatefulWidget의 차이

StatelessWidget은 부모 위젯의 build 메서드에서 생성되고 UI의 해당 부분이 어떤 이유로든 다시 빌드되어야 할 때까지만 존재함.

또한 이 위젯은 필요한 매개변수를 받을 수 있는 선택적 생성자(optional constructor)와 더 많은 위젯을 조합하는 build 메서드를 가지고 있고, 이는 UI의 한 측면을 설명하고 해당 섹션이 표시될 때까지 사용됨.

반면에 StatefulWidget은 더 많은 기능을 가지고 있는데 기술적으로 보면, StatefulWidget의 “위젯” 부분 자체는 StatelessWidget과 마찬가지로 생명력이 없고 언제든지 교체될 수 있지만, StatefulWidget은 더 오래 지속되는 중요한 상태(State) 객체에 의해 뒷받침됨.

애니메이션, TextEditingController처럼 오래 지속되는 리소가 필요하거나 위젯이 애플리케이션 상태의 변화를 관리해야 할 때 StatefulWidget을 사용함.

StatefulWidget은 StatelessWidget과 외형도 다른 모습을 보이는데 build 메서드가 위젯이 아닌 State 객체로 이동된 것이 그 예임.

이 State 객체는 두 번째 트리, 엘리먼트 트리에서 관리됨.

엘리먼트 트리

엘리먼트 트리(Element Tree)는 위젯 트리 뒤에 존재하며 위젯과 Flutter 내부의 렌더링 계층을 연결하는 수명이 긴 객체인 엘리먼트(element)들로 구성됨.

엘리먼트는 프레임마다 위젯 트리의 변화를 분석하고, 그 변화가 의미하는 바를 판단한 뒤, 필요한 모든 처리를 해결함. 그리고 그 엘리먼트가 바로 BuildContext 임.

위젯은 궁극적으로 엘리먼트, 요소를 생성하고, 생성된 요소는 buid 메서드에서 중요한 정보를 조회하는데 다시 사용할 수 있게 됨. 이 흐름은 다음과 같음.

새 위젯이 위젯 트리에 처음 추가 되면, 프레임 워크는 해당 위젯의 createElement 메서드를 호출하고 생성된 요소는 엘리먼트 트리에 연결됨.

이로 인해 위젯 트리와 엘리먼트 트리는 항상 동일한 형태를 유지함.

그런 다음에 플러터는 위젯 트리를 따라 재귀적으로 계속 탐색하면서 해당 위젯의 build 메서드를 호출하게 됨. 그리고 build 메서드를 호출하는 주체가 바로 엘리먼트임.

엘리먼트는 자기 위젯의 build 메서드를 호출하면서 빌드 콘텍스트의 매개변수로 자기 자신을 전달함.

이렇게 하면 더 많은 위젯이 생성되고 이 과정이 계속 반복됨.

블록이 애니메이션 중에 색상이 바뀐다고 해보면 가상 위젯 트리와 이를 뒷받침하는 엘리먼트 트리가 있을 텐데 최상단의 위젯은 애니메이션 동안 매 프레임마다 변경되고 다시 빌드되게 됨.

이 재빌드 과정에서 모든 하위 위젯은 제거되고 새 위젯으로 대체되는데 반면에 엘리먼트 트리는 가능한 한 오래 유지됨.

위에 있는 예제를 보면 새 위젯들이 기존 엘리먼트와 같은 위치에서 짝지어지게 되는데 항상 이런 것은 아님. 위에 있는 예제의 트리의 최상단 노드는 처음부터 StatefulWidget이였는데 이 위젯으로 인해 현재 색상 값과 시간에 따른 변경 로직이 State 객체에 저장되어 있어서 엘리먼트가 State 객체를 항상 준비된 상태로 유지하고 있었음.

렌더 트리

세 번째 위젯 유형인 RenderObjectWidget은 렌더 오브젝트(render object)를 생성할 수 있고 이 위젯은 앞선 두 위젯과는 다르게 build 메서드를 가지고 있지 않지만 대신 createRenderObject, updateRenderObject 이렇게 두 가지 메서드를 가지고 있음.

렌더 오브젝트들은 플러터의 마지막 주요 트리인 렌더 트리를 구성하는데, 렌더링 객체는 위젯 값을 페인팅 호출로 변환하며, 이 호출은 최종적으로 GPU에서 실행되게 됨.

렌더링 객체는 엘리먼트처럼 수명이 긴 객체이고 직접 커스텀 렌더 오브젝트를 작성할 수도 있음.

플러터 아키텍처의 핵심은 여러 단계를 거치고, 고도로 계층화되고, 추상화된 렌더링 루프이며 각 레이어는 데이터를 조금씩 변환하여 운영 체제가 화면에 표시할 수 있는 픽셀 버퍼에 가까워지게 만듦.

렌더링 프로세스의 단계에서 위젯 트리의 모든 렌더링 객체 위젯은 렌더링 객체를 생성함으로써 개념적으로 한 단계 더 나아가며 이러한 렌더링 객체는 트리 구조로 조립되고 위젯의 속성을 사용하여 접근성, 레이아웃, 렌더링 및 히트 테스트를 포함한 여러 핵심 작업을 수행하게 됨.

페인팅은 픽셀 버퍼를 생성하는 게 아닌 드로잉 명령만 생성하며, 또한 이 명령은 Skia 혹은 Impellar에 의해 나중에 그려짐.

이 외에도 다음과 같은 트리들이 존재함.

  • 접근성을 위한 시맨틱 트리
  • 키포드 포커스를 위한 포커스 트리
  • UI 합성을 위한 레이어 트리
반응형