Coaspe

Flutter - StatefulWidget 본문

Flutter/API

Flutter - StatefulWidget

Coaspe 2023. 2. 17. 13:58

변할 수 있는 state를 가지는 위젯입니다.

 

State는 다음과 같은 정보입니다.

(1) 위젯이 build 될 때 동기적으로 read 될 수 있습니다.

(2) 위젯의 lifetime 동안 바뀔 수 있습니다.

이러한 state가 변경되면, State.setState를 사용하여 해당 state가 즉시 알려질수있도록 하는 것은 위젯 implementer가 구현해야합니다.

 

Stateful 위젯은 유저 인터페이스를 보다 구체적으로 설명하는 다른 위젯의 constellation(연관이 있는 무리)을 구축하여 유저 인터페이스의 일부를 설명하는 위젯입니다. building 프로세스는 유저 인터페이스의 설명이 완전히 자세해질 때까지 재귀적으로 진행됩니다.(e.g. RenderObjectWidgets는 구체적인 RenderObjects을 설명하는 RenderObjectWidgets로 구성되어 있습니다.)

 

Stateful 위젯은 유저 인터페이스의 부분이 동적으로 바뀔 수 있을 때 유용합니다. e.g. 내부 클럭 기반 상태 또는 일부 시스템 상태에 의존하기 때문에. 객체 자체의 구성 정보와 위젯이 inflated(메모리에 올려진)된 BuildContext에만 의존하는 compositions의 경우 StatelessWidget을 사용하세요.

 

 

StatefulWidget 인스턴스는 스스로 불변합니다. 그렇기 때문에 StatefulWidget와 분리되고 createState 메소드로 생성되는 State 객체 (1)나 State가 subscribes하는 Stream or ChangeNotifier 같은 객체(2)에 변할 수 있는 상태를 저장합니다. 그리고 (2)에서 그 상태의 객체가 StatefulWidget에 final 필드로 저장됩니다.

 

프레임워크는 StatefulWidget를 inflates 할 때마다, createState를 호출합니다. 그리고 그것은 만약 해당 위젯이 트리의 여러 곳에 삽입 되었다면, 다수의 State 객체가 동일한 StatefulWidget과 연관되어 있다는 것을 의미합니다.

유사하게, 만약 StatefulWidget가 트리에서 지워지고 나중에 트리에 다시 삽입 된다면, 프레임워크는 createState를 다시 호출하여 새로운 State 객체를 생성함으로써 State 객체의 생명주기를 단순화합니다.

 

StatefulWidget는 creator가 keyGlobalKey를 사용한다면, 트리에서 움직일 때 동일한 State 객체를 사용할 수 있습니다. GlobalKey를 가지는 위젯은 트리의 한 위치에서만 사용 될 수 있고, GlobalKey를 사용하는 위젯은 하나의 element에만 연결되어 있습니다. Flutter는 위젯과 연결된(고유한) 이전의 위치에서 새로운 위치로 해당 위젯과 연결된 서브트리를 grafting(붙이는 것) 하므로써 global key를 사용하여 위젯을 트리 안에서 움직일 때 이런 특성을 사용합니다.(새로운 위치에 다시 서브트리를 만드는 것 대신) StatefulWidget와 연결된 State 객체들은 서브 트리의 나머지 부분과 함께 grafted 됩니다. 즉, State 객체는 새 위치에서 다시 만들어지는(recreated) 대신 재사용(reused)됩니다. 그러나, grafting이 잘 작동하려면 위젯이 이전 위치에서 제거되었던 동일한 애니메이션 프레임의 새 위치에 위젯을 삽입해야 합니다.

 

Performance considerations

StatefulWidgets는 두개의 기본 카테고리를 가집니다.

 

첫 번째는 State.initState에서 리소스를 할당하고, State.dispose에서 리소스들을 처리합니다. 하지만, InheritedWidgets or State.setState 호출에 의존하지 않습니다. 그런 위젯들은 주로 어플리케이션의 루트에서 사용되고, ChangeNotifiers, Streams나 다른 객체들을 사용하여 서브 위젯들과 커뮤니케이션합니다. 이런 패턴을 따르는 Stateful 위젯들은 한번 빌드되고 업데이트되지 않기 때문에 상대적으로 가볍습니다.(CPU나 GPU 사용이 적다는 뜻). 따라서, 그들은 다소 복잡하고 깊은 build 메소드를 가질 수 있습니다.

 

두 번째는 State.setState을 사용하거나, InheritedWidgets에 의존하는 위젯입니다. 이 위젯들은 보통 lifetime 동안에 많이 rebuild하므로, rebuilding의 영향을 최소화하는 것이 중요합니다. (그런 위젯들은 State.initState or State.didChangeDependencies을 사용할 수도 있고, 리소스들을 할당하지만 가장 중요한 부분은 rebuild하는 것 입니다.)

 

Stateful 위젯을 rebuilding하는 것의 영향을 최소화하는 기법들이 있습니다.

 

  • Leaves(위젯의 말단)로 state를 푸쉬하세요. 예를 들면, 만약 페이지가 시계를 가지고 있다고 하면, 페이지의 맨 위에 state를 둬서 시계가 tick 할 때마다 전체 페이지를 rebuilding하는 것 보다, 시계를 더 자세하게 만들어서 시계만 업데이트하게 하는 것이 더 효율적입니다.
  • build 메소드와 build 메소드가 생성하는 위젯에 의해 딸려서 생성된 노드 수를 최소화하세요. 이상적으로는, stateful 위젯은 하나의 위젯을 생성하고 그 위젯은 RenderObjectWidget 입니다.(명백히 이건 항상 현실적이지 않지만, 위젯이 이런 이상향에 가까워 질수록, 점점 효율적으로 바뀝니다.)
  • 만약에 서브트리가 변하지 않는다면, 해당 서브트리를 나타내는 위젯을 캐쉬하고 매번 재사용 합니다. 이렇게 하기 위해, 위젯을 final state 변수에 할당하고, build 메소드에서 재사용하세요. 이것은 동일한 위젯을 새로 만드는 것 보다 훨씬 효율적입니다. 또다른 캐싱 전략은 위젯의 변하는 부분을 자식 파라미터를 받는 StatefulWidget으로 추출하는 것 입니다.
  • 가능하다면 const 위젯을 사용하세요.(이건 위젯을 캐싱하고 재사용 하는 것과 동일합니다.)
  • 서브트리에서 위젯의 타입을 바꾸거나, 생성된 서브트리의 깊이를 바꾸려고 하지마세요. 예를 들면,  IgnorePointer로 감싸진 자식 또는 그 자식을 반환하는 대신 항상 자식 위젯을 IgnorePointer로 감싸거나, IgnorePointer.ignoring 속성을 바꾸세요. 서브트리의 깊이를 바꾸는 것은 전체 서브트리를 rebuilding, laying out, painting을 요구하는 반면 단지 속성을 바꾸는 것은 렌더 트리에 최소로 필요한 변화만 일으킵니다.(예를 들어, IgnorePointer의 경우 layout과 repaint가 필요하지 않습니다.)
  • 만약 어떤한 이유로 깊이가 변경되어야 한다면, stateful 위젯의 lifetime 동안 일정하게 유지되는 GlobalKey를 가지고 있는 위젯에서 서브 트리의 공통 부분을 감싸는 것을 고려해 보세요. (다른 위젯들에게 키가 할당되기 어렵다면, KeyedSubtree를 사용하는 것이 좋을 것 입니다.)
  • UI의 재사용 가능한 부분을 만들려고 할 때, helper 메소드를 사용하는 것 보다 widget을 사용하는 게 더 좋을겁니다. 예를 들어, 만약 위젯을 build하기 위한 함수가 있다고 해봅시다. State.setState 호출은 Flutter가 반환된 wrapping 위젯을 전부 rebuild 하게 합니다. 만약 Widget을 대신 사용하면, Flutter는 업데이트 되어야 할부분만 효율적으로 re-render 할 수 있습니다. 더 효율적인 경우로, 만약 생성된 위젯이 const라면, Flutter는 대부분의 rebuild 작업의 대부분을 할 필요가 없어집니다.

 

밑의 비디오는 helper 메소드보다 Widget을 사용하는 것이 왜 더 좋고, const 생성자가 왜 중요한지 설명합니다.

 

다음은 YellowBird라는 stateful widget 서브클래스의 뼈대입니다.

코드에서, State는 실제 state를 가지지 않습니다. State는 보통 private 멤버로 표시됩니다. 그리고 보통 위젯들은 더 많은 생성자 인자를 가지고, 각각은 final 프로퍼티와 대응됩니다.

 

다음 코드에서는 내부 state와 그것을 변경 할 수 있는 메소드와 color, child 멤버를 가지는 Bird라는 위젯이 있습니다.

 

관습적으로, 위젯 생성자들은 named 인자를 사용합니다. 또한, 첫 번째 인자는 key이고 마지막 인자는 child, children 또는 둘과 동일한 인자 입니다.

 

See also:

  • State, where the logic behind a StatefulWidget is hosted.
  • StatelessWidget, for widgets that always build the same way given a particular configuration and ambient state.
  • InheritedWidget, for widgets that introduce ambient state that can be read by descendant widgets.

상속 구조

생성자

StatefulWidget({Key? key})

'Flutter > API' 카테고리의 다른 글

Flutter - RestorationMixin<S extends StatefulWidget>  (0) 2023.02.17
Flutter - InheritedWidget  (0) 2023.02.17
Flutter - Object  (0) 2023.02.17
Flutter - DiagnosticsNode  (0) 2023.02.17
Flutter - BuildContext  (0) 2023.02.17
Comments