Weekly Flutter

flutter 렌더링 과정에 대해서 알아보자

taby 2023. 7. 13. 12:34

우리가 작성한 flutter 코드는 어떤 과정을 거쳐서 화면에 표시되는걸까? 

엉성하게 보고 대충 이렇군..넘어가다가 제대로 알아보고자 마음먹고 작성합니다..

플러터는 부드러운 UI를 위해 1초에 60프레임을 목표로 합니다. 그 뜻은 1초에 최소 60번 화면을 다시 그린다는 의미입니다. 

플러터는 이런 빠른 렌더링 성능을 보장하기 위해 build 단계에서 widgetTree elementTree 만들어 사용하고,

layout 단계에서 RenderObjectTree 생성합니다. 아래에 자세히 설명하겠습니다.

위와 같이 총 3개의 트리를 사용하는 이유는 한번 화면을 그린 후에는 전체를 다시 재렌더링 하는게 아닌 필요한 부분만 다시 그리기 위해서라고 합니다.  

 

플러터의 모든 것은 위젯으로 이루어진다 라는 말을 들어보셨을 거 같습니다.

플러터의 공식 문서에서는 위젯은 immutable하다고 말합니다. 그렇다면 데이터들이 서로 상호작용을 하면서 값을 바꿔야하는 위젯들이 어떻게 1초에 60번이라는 빠른 시간에 화면을 다시 그릴 수 있을까요?

위젯은 불변하지만 위젯트리는 언제든지 변경 가능하기 때문입니다.

위젯트리는 flutter개발자들이 직접 수정하고 만질 수 있는 트리로 속성에 대한 정보를 포함하고 있습니다.(fintSize, text, color 등등)

생성 및 파기 비용이 매우 적게 들도록 설계되어 위젯트리의 업데이트에 바로바로 대응할 수 있습니다. 

저희가 사용하고 있는 vsCode에서도 widgetInspector 통해서 위젯트리를 쉽게 확인할 있습니다.

main()에서 처음 runApp()을 호출하면 flutter는 build 함수를 통해 위젯을 리턴합니다. 

build 함수에서 리턴한 위젯은 위젯트리로 들어가게 됩니다.

 

위젯 내부를 살펴보겠습니다.

flutter는 위젯 트리를 따라 내려가면서 위젯을 호출하여 createElement()를 통해 해당 element 객체를 포함하는 elementTree를 만들게 됩니다.

createElement() 인스턴스를 구체화해주는 함수로 element 생성되게 되면 element 위젯트리 내에서 해당 위젯이 어디에 존재하는지 알리는 역할을 합니다.

widgetTree와 함께 생성된 ElementTree는 widget과 1:1 연결이 됩니다.

widgetTree 가지고 있는 속성들을 실제로 변경하는 것은 바로 element입니다. 

위젯의 내용을 보고 element는 실제로 그려질 instance를 생성합니다. 

위젯에서 상태 변화를 관장하는 mount, update, markneedsBuild 등등의 함수들은 모두 element가 가지고 있는 함수로 실제로
state변화를 주는 것은 element가 한다는 것을 알 수 있습니다.

Element들은 재사용이 가능한데 재사용 가능여부를 확인하기 위해 canUpdate()함수를 호출합니다. 

위 함수를 호출하여 재사용이 가능하면 tree에 위치한 element를 그대로 사용합니다.

그렇지 않을 경우에는 element를 tree내에서 unmount(제거)하고 새로운 element를 mount(추가)합니다. 

우리가 같은 위젯의 상태를 변경할때 Type 같으면 element 변경되지 않기 때문에 위젯의 State 변경되지 않는 경우가 있는데,

이때 우리는 key 사용하여 변경합니다. 

 

각각의 element들은 createRenderObject() 함수를 가지고 있습니다.

이 함수를 통해 Layout단에서 RenderObjectTree가 생성됩니다. 

layout단계는 RenderObjectTree를 보며 위젯이 어느 위치에 그려질지 어떤 색상과 사이즈를 가질지 결정하는 단계입니다. 

flutter의 레이아웃 작업은 1프레임 당 1번 일어납니다.

RenderObjectTree는 실제 UI를 그리기 위한 요소로 flutter에서 화면을 그릴때 Widget과 element를 보는 것이 아닌 이 RenderObjectTree를 보며 화면을 그립니다.

이 트리가 가지고 있는 정보는 무겁기 때문에 위젯이 완전히 바뀌지 않는 이상 새로 만들지 않습니다.

대신에 안에 있는 내용을 바꾸는 방식으로 작동합니다. 

앞서 언급했던 canUpdate() 함수를 통해서 내용이 변경됬다는 것을 감지하게 되면 updateRenderObject() 메소드를 호출하여 렌더 오브젝트의 내용을 변경합니다. 

이 RenderObject는 위젯과 달리 mutable 하기 때문에 런타임중에 수정이 가능합니다. 

 

flutter 렌더링은 이렇게 세개의 트리를 거치기 때문에 퍼포먼스적으로 좋은 성능을 있습니다.