생명주기는 앱이나 앱의 각 화면이 생성되고 소멸될 때까지의 과정을 의미한다. 대부분의 UI 프레임워크나 라이브러리는 컴포넌트의 생성, 업데이트, 소멸 등의 단계를 가지고 있으며, 이런 단계를 생명주기 메소드라고 부른다.
하지만 Flutter 에는 명시적인 "Life-Cycle"이라는 개념이 존재하지 않는다.
다만, 위젯의 상태 변화와 관련된 StatefulWidget
의 생명 주기가 일반적인 생명 주기처럼 동작한다.
특히 Flutter에서 상태 관리
와 위젯 트리를 업데이트하는 방식
이 생명 주기의 중요한 부분이다.
StatefulWidget 은 State객체와 연결되어 있으며, 이 State객체에는 다음과 같은 생명 주기 메서드가 포함되어 있다.
StatefulWidget을 생성하면 호출되며, 상태 관리용 객체를 생성한다.
class MyStatefulWidget extends StatefulWidget {
_MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
Widget build(BuildContext context) {
return Container();
}
}
StatefulWidget이 처음 생성될 때 호출되며, 위젯의 상태를 관리하는 State 객체를 생성
이 메서드는 위젯마다 한 번만 호출.
상태 초기화 및 State 클래스와 연결.
State객체 _MyStatefulWidgetState
를 생성하고 반환.
initState는 위젯이 생성될 때 한 번만 호출되며
초기화 작업(예: 변수 초기화, 데이터 로드, 이벤트 리스너 설정 등)을 수행.
플러터에 의해 실행되며 StatefulWidget의 2번째 클래스의 super class인 State객체가 생성될 때 실행된다.
class MyStatefulWidget extends StatefulWidget {
_MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
String _message = "";
void initState() {
super.initState();
_message = "Hello, Flutter!";
print("initState called: $_message");
}
Widget build(BuildContext context) {
return Center(
child: Text(_message),
);
}
}
State 객체가 생성된 후 한 번 호출됨. 상태 초기화나 API 호출 같은 1회성 작업을 수행할 때 유용함.
super.initState()를 반드시 호출해야 됨.
초기 데이터를 로드하거나 Stream 또는 Controller를 설정할 때.
위젯이 의존하는 InheritedWidget
이 변경되었을 때 호출된다.
초기화 직후에도 호출된다.
class MyStatefulWidget extends StatefulWidget {
_MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
void didChangeDependencies() {
super.didChangeDependencies();
print("didChangeDependencies called");
}
Widget build(BuildContext context) {
return Text('Check console for logs.');
}
}
위젯이 의존하는 InheritedWidget이 변경되었을 때 호출.
State가 생성된 직후에도 호출.
Theme 또는 Locale 같은 외부 의존성이 바뀔 때 반응.
위젯의 UI를 구성하는 핵심 메서드로, 상태가 변경될 때( setState에 의하여 실행될 때 )마다 호출.
혹은 Widget이 처음 build함수가 실행될 때 호출
class MyStatefulWidget extends StatefulWidget {
_MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
int _counter = 0;
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Build Example")),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("Counter: $_counter"),
ElevatedButton(
onPressed: () {
setState(() {
_counter++;
});
},
child: Text("Increment"),
),
],
),
),
);
}
}
버튼을 클릭할 때마다 화면이 업데이트되며 build()가 호출.
이 메서드는 화면을 다시 그리는 데 사용된다.
상태를 기반으로 화면을 그릴 때.
부모 위젯이 변경되었을 때 호출.
WidgetsBindingObserver를 통해서도 호출 가능.
class MyStatefulWidget extends StatefulWidget {
final String title;
MyStatefulWidget({required this.title});
_MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
void didUpdateWidget(covariant MyStatefulWidget oldWidget) {
super.didUpdateWidget(oldWidget);
print("didUpdateWidget: ${oldWidget.title} -> ${widget.title}");
}
Widget build(BuildContext context) {
return Text(widget.title);
}
}
부모에서 title을 변경하면 호출.
이전 위젯과 새 위젯의 차이를 확인하고 작업을 수행함.
위젯의 프로퍼티가 변경되었을 때 작업이 필요할 경우. (사용 예시)
상태가 변경되었음을 Flutter에 알리고, UI를 재구성하도록 트리거.
class MyStatefulWidget extends StatefulWidget {
_MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
String _message = "Hello";
void _updateMessage() {
setState(() {
_message = "Hello, World!";
});
}
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(_message),
ElevatedButton(
onPressed: _updateMessage,
child: Text("Update Message"),
),
],
);
}
}
버튼을 클릭하면 메시지가 "Hello, World!"로 변경됨.
이 메서드는 직접 호출해야 하며, build()를 다시 호출하도록 요청합니다.
버튼 클릭, API 응답 등을 통해 화면을 업데이트할 때.
class MyStatefulWidget extends StatefulWidget {
_MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
void deactivate() {
super.deactivate();
print("deactivate called");
}
Widget build(BuildContext context) {
return Container();
}
}
위젯이 위젯 트리에서 제거될 때 호출됨.
특정 위젯이 더 이상 사용되지 않음을 나타냄.
자식 위젯이 변경될 때, 이를 감지.
탭 전환이나 위젯 트리 변경 시 호출됨.
Widget이 삭제되기 전에 실행. OR WidgetsBindingObserver를 통해 conditionally 하게 렌더링 된다든지 할 때도 사용.
class MyStatefulWidget extends StatefulWidget {
_MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
late TextEditingController _controller;
void initState() {
super.initState();
_controller = TextEditingController();
}
void dispose() {
_controller.dispose(); // 메모리 누수 방지
print("dispose called");
super.dispose();
}
Widget build(BuildContext context) {
return TextField(controller: _controller);
}
}
State 객체가 영구적으로 제거되기 전에 호출됨.
Controller 해제, Stream 구독 취소, 메모리 정리를 수행함.
TextEditingController, AnimationController 등을 정리할 때.
위 메소드들은 프레임워크나 라이브러리에서 자동으로 호출되며, 우리는 이 메소드를 오버라이드하여 각 단계에서 수행할 작업을 정의할 수 있다.
StatelessWidget은 상태가 없기 때문에 단순히 build() 메서드만 호출됨.
Flutter Life-Cycle이 중요한 이유
- 리소스 관리: dispose()를 사용해 메모리 누수를 방지.
- 상태 초기화: initState()에서 초기 상태를 설정.
- 효율적인 UI 업데이트: setState()와 build()를 통해 필요한 부분만 다시 렌더링.