Java / Spring
Flutter - dispose() 본문
dispose() 가 필요한 이유:
- 입력 값에 대한 변수를 생성할 때 TextEditingController() 와 같은 함수를 호출해서 입력할 변수 데이터에 초기화 시키는 경우
- TextEditingController 는 단순한 값 저장 변수가 아니라 Stream 내부에서 키 입력 이벤트를 구독하는 리스너와 같은 리소스를 사용한다. StatefulWidget 이 화면에서 사라져도 이 컨트롤러가 계속 메모리에 남아 있으면, 사용하지 않는 리소스를 계속 점유하게 되어 메모리 누수나 예상치 못한 동작이 생길 수 있기 때문에 dispose() 를 통해 내부 리소스를 해제해 줘야 한다.
dispose() 를 명시적으로 오버라이드 해야 하는 경우
1. Controller 관련 이벤트 선언 시
- TextEditingController
- ScrollController
- TabController
- PageController
- AnimationController
2. Stream 관련 이벤트 선언 시
- StreamSubscription
- BLoC, RxDart, WebSocket 등에서 사용하는 구독
3. Timer / 주기 작업
- Timer
- Timer.periodic
- Ticker
4. Focus / Node 관련
- FocusNode
- FocusScopeNode
5. 기타 수동 해제 리소스
- 데이터베이스 연결 객체 (ex. sqflite의 Database 인스턴스)
- Platform channel에서 생성한 네이티브 리소스
- 지도/카메라 컨트롤러 (GoogleMapController, CameraController 등)
- 비디오/오디오 플레이어 컨트롤러
dispose() 를 쓰지 않아도 되는 경우
- 단순 변수(String, int, bool 등)
- 단순 모델 객체 (MyModel, DTO 등, GC가 알아서 정리)
- const 위젯 / 값
- 네트워크 요청 후 응답 받고 끝나는 API 호출(단, 스트림형 API는 예외)
dispose() 동작 방식
https://docs.flutter.dev/cookbook/forms/text-field-changes << 공식문서에서도 dispose() 권장
- dispose() 는 플러터에서 State 객체가 더 이상 필요 없을 때 자동으로 호출 되므로, 이 타이밍에 dispose() 를 불러서 내부 리소스를 해제한다.
dispose() 를 사용하지 않으면 발생하는 문제
- 화면을 여러 번 갔다 왔다 하면, 이전 화면의 TextEditingController 가 계속 쌓임
- 입력 이벤트 리스너가 중복 실행될 수 있음
- 장기적으로 메모리 사용량이 불필요하게 증가
사용 예시) 아래와 같이 게시물을 등록하기 위한 Upload 라는 커스텀 위젯이 있다고 할 때
class Upload extends StatefulWidget {
const Upload({super.key, required this.imageFile});
final File imageFile;
@override
State<Upload> createState() => _UploadState();
}
class _UploadState extends State<Upload> {
...
}
class _UploadState extends State<Upload> {
final TextEditingController _contentController = TextEditingController();
final TextEditingController _userController = TextEditingController();
final formattedDate = DateFormat('MMM d').format(DateTime.now());
(* State 내부에 업로드 시 입력할 TextController() 를 선언, 위젯이 초기화 될 때 해당 변수도 함께 메모리에 추가 된다.)
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('이미지 업로드')),
body: Column(
children: [
Image.file(widget.imageFile),
const SizedBox(height: 16),
TextField(
controller: _contentController,
decoration: const InputDecoration(
labelText: '내용을 입력해주세요',
border: OutlineInputBorder(),
),
),
TextField(
controller: _userController,
decoration: const InputDecoration(
labelText: '이름을 입력해주세요',
border: OutlineInputBorder(),
),
),
ElevatedButton(
onPressed: () {
final newPost = {
"id": DateTime.now().millisecondsSinceEpoch,
"image": widget.imageFile.path,
"likes": 0,
"date": formattedDate,
"content": _contentController.text,
"liked": false,
"user": _userController.text
};
Navigator.pop(context, newPost);
},
child: const Text("저장"),
),
],
),
);
}
그리고 위와 같이 Scaffold() 내부에 TextField() 에서 위젯이 랜더링 될때 초기화 시켜놓은 TextController() 의 변수를 입력하면,
이 변수가 newPost {} 내부에 content 와 user 라는 key 값에 value 로 초기화 된 뒤 사용자가 Text("저장") 을 누르면 Navigator.pop() 이 동작하면서 dispose() 가 실행된다.
(+ Navigator.pop() 은 코드에서 저장 버튼의 onPressed 콜백 내부에 있기 때문에 사용자가 "저장" 버튼을 눌렀을 때 바로 실행 됨)
* dispose() 선언 예시
class Upload extends StatefulWidget {
const Upload({super.key, required this.imageFile});
final File imageFile;
@override
State<Upload> createState() => _UploadState();
}
class _UploadState extends State<Upload> {
final TextEditingController _contentController = TextEditingController();
final TextEditingController _userController = TextEditingController();
final formattedDate = DateFormat('MMM d').format(DateTime.now());
@override
void dispose() {
_contentController.dispose();
_userController.dispose();
super.dispose();
}
동작 흐름
1. 사용자가 특정 Navigator.pust() 로 Upload 위젯을 랜더링 시킴
2. _UploadState 객체가 생성, initState() => build() 실행
3. TextEditingController 2개 (_user, _content) 가 메모리에 올라감
4. 사용자가 저장 버튼을 누르면 Navigator.pop() 이 동작한다. 이 때, 화면이 네이게이션 스택에서 제거 되고, 플러터프레임워크는 이 위젯의 State를 더 이상 사용할 필요가 없다고 판단하고 dispose() 를 이 시점에 자동으로 호출한다.
'Front' 카테고리의 다른 글
| Flutter - 많이 사용하는 명령어 (0) | 2025.11.22 |
|---|---|
| Flutter : {Super.key?} (0) | 2025.07.28 |
| [VUE/Composition API] Axios + Ref() (0) | 2025.03.24 |
| [Vue] 상태관리, State & mutaions (0) | 2025.02.20 |
| [Vue] Axios (0) | 2025.01.06 |
