티스토리 뷰
[Flutter] Widget과 Element - 2부 Widget Tree와 Element Tree 그리고 LifeCycle
윈드. 2022. 8. 24. 21:49보통 안드로이드 개발을 하다 플러터를 접하게 되면 가장 먼저 찾아보는 개념이 LifeCycle이다.
안드로이드에서는 Activity나 Fragement의 LifeCycle과 상태 변화에 따라 적절한 함수들이 호출된다. 이 함수들을 잘 이용해서 상황에 맞는 프로그램을 기능들을 추가하게 되는데 플러터에서도 이와 유사한 개념이 없을까 하고 찾아보게 된다.
이때 가장 먼저 접하게 되는 정보들이 StatefulWidget의 Lifecycle일것이다.
위 다이어그램만 보면 StatefulWidget에 그럴듯한 LifeCycle이 있는것 처럼 보인다.
하지만 정확히 이야기 하자면 StatefulWidget은 LifeCycle을 가질 수 없다. 왜냐 하면 모든 Widget은 Immutable 하며 build과정에 항상 새롭게 생성되기 때문이다.
결국 StatefulWidget의 LifeCycle은 State의 LifeCycle이 되는데 State도 StatefulElement의 LifeCycle에 직접적인 영향을 받기 때문에 LifeCycle에 대해서 이야기하려면 Widget이 아닌 Element의 LifeCycle를 알아야 한다.
Element의 LifeCycle
Element는 아래와 같이 부모 Element에 의해 생성/재사용/제거 된다.
이 과정은 ElementTree에 mount/unmount 되거나 rebuild 되는 것을 의미한다.
ParentElement - UpdateChild
우선 부모 Element에서 부터 시작해 보자 부모 element는 build 될 때 자신의 자식도 buld 되도록 해야 하므로 updateChild을 호출해서 자식들이 빌드 되도록 해야한다.
이때 자식 Element를 새롭게 생성해서 mount거나, 기존에 이미 사용하던 element 재사용 하기도한다.
Element의 생성
1. 생성 / mount()
부모 element는 자식 element가 재사용 가능한지 확인 후 재사용이 불가능할 경우 새로운 Element를 생성한 후 Mount 한다.
final child = newWidget.createElement();
child.mount(this, slot);
// mount될때 _firstBuild가 수행된다.
@override
void mount(Element? parent, Object? newSlot) {
super.mount(parent, newSlot);
_firstBuild();
}
2. _firstBuild() : 최초 빌드되기 전
Element가 처음 mount 된 후 빌드되기 전에 호출되는 함수로 Element가 첫 빌드되기 전에 수행해야 하는 로직이 있을 경우 하위 구현체(StatelessElement / StatefulElement 등)에서 추가 동작을 구현해 주고 있다.
// mount된 element는 _fristBuild를 호출해 자신의 첫 빌드를 수행한다.
// _firstBuild()는
_firstBuild()
// StatefulElement의 _fisrstBuild()와 build()
// state의 초기함수들을 호출한 후 state의 build를 호출함
@override
void _firstBuild() {
state.initState();
state.didChangeDepencencies();
super._firstBuild();
// _firstBuild를 호출하면 아래 함수들이 호출됨
// _firstBuild()-> rebuild() -> performRebuild() -> build()
}
@override
Widget build() => state.build(this);
// StatelessElement의 _firstBuild()와 build()
// 별도의 동작없이 widget의 build를 호출함
@override
void _firstBuild() {
super._firstBuild();
// _firstBuild를 호출하면 아래 함수들이 호출됨
// _firstBuild()-> rebuild() -> performRebuild() -> build()
}
@override
Widget build() => widget.build(this);
Element의 재사용
element의 재사용 가능 여부를 확인 (Widget.canUpdate) 후 재사용이 가능한 경우
1. update()
element의 update함수를 호출한다.
이 함수는 내부적으로 rebuild를 호출해서 element가 다시 빌드되도록 한다.
Element 제거와 소멸
더 이상 사용하지 않는 child element는 이제 element tree에서 제거되어야 한다.
1. deactivate()
build 과정에 _InactivateElements객체에 불필요한 element들을 추가하게 되는데
여기에 추가되는 시점에 element은 deactivate 된다.
2. unmount()
위 과정에서 _InactivateElements에 모아 둔 deactivate된 element을 build마지막 과정에
모두 unmount 하게 되며, element는 더 이상 사용할 수 없는 상태가 되어 소멸하게 된다.
State의 LifeCycle은 Element LifeCycle의 그림자다.
위에서 element의 생성, 재사용, 소멸 과정을에 대해서 간단하게 알아보았다.
사실 lifecycle이 복잡하지 않지만 여러 element구현체들에서 추가 기능이 포함되면서 조금 더 복잡한 내부 과정을 가지게 된다.
특히 우리가 잘 알고 있는 state의 LifeCycle의 경우 StatefulElement에서 Element의 함수들을 재정의 해서 사용하고 있는데
Element LifeCycle과 State LifeCycle을 연결시켜 보면 Element와 State의 관계를 좀더 명확하게 알수 있다.
마치며
Widget Immutable하기 때문에 LifeCycle을 가질 수 없습니다. 그리고 StatefulWidget의 State 역시 LifeCycle을 가지는 것처럼 보이지만 사실은 Element LifeCycle의 그림자입니다.
만약 개발 중 원치 않는 동작이 발생하거나 Element(state)가 재사용되지 않고 항상 생성되어 속도 저하가 발생한다면 위 과정을 한 번쯤 생각해 보시고 Element를 재사용할 수 있는 형태로 Widget들이 구성되어 있는지 살펴볼 필요가 있습니다.
-> 3부 GlobalKey와 LocalKey 에서 계속
'Flutter' 카테고리의 다른 글
[Flutter] Widget과 Element - 4부 결론 (0) | 2022.09.29 |
---|---|
[Flutter] Widget과 Element - 3부 GlobalKey와 LocalKey (0) | 2022.09.20 |
[Flutter] Widget과 Element - 1부 Element를 알아야 하는 이유 (3) | 2022.08.09 |
[Flutter] Multiple Flutter : FlutterEngine의 다양한 생성과 활용 (1) | 2022.07.13 |
[Flutter] Freezed : 우리는 왜 immutable 객체를 사용해야 하는가? (0) | 2022.07.06 |
- Total
- Today
- Yesterday
- MVVM
- enum member
- Android
- Mutiple Flutter
- LocalKey
- Flutter LifeCycle
- DART
- Widget Tree
- freezed
- Element LifeCycle
- json_serializable
- Flutter TDD
- dart enum
- flutter i18n
- Flutter3.0
- flutter2.0
- RenderObject
- dart 2.17
- flutter mvvm
- FlutterEngine
- flutter element
- widget element
- navigator
- flutter 다국어처리
- StatefulWidget LifeCycle
- Flutter
- python3
- flutter l10n
- flutter_secure_storage
- Route
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |