작성자 | 임혜진 |
일 시 | 2024. 3. 14 (목) 18:00 ~ 21:00 |
장 소 | 복지관 b128-1호 |
참가자 명단 | 임혜진, 이재영, 성창민, 김명원, 장원준 |
사 진 | ![]() |
지난 번 프로젝트 때 플러터를 사용하면서 가장 어려웠던 것은 위젯의 생명주기였다. 예를 들면 프로필 관리에서 프로필 캐릭터를 변경해주면 바로 내 프로필이 변경되어야 하는데, 서버 상으로만 변경되고 화면에는 바로 반영이 안된다든가 하는 이슈가 많이 생겨났다. 이를 위해 위젯의 생명주기에 대해 공부해보고자 한다.
플러터 앱을 구성하는 위젯은 Stateless Widget과 Stateful Widget으로 구분할 수 있다. Stateless Widget은 다시 갱신할 필요가 없는, 새로고침할 필요가 없는 위젯을 말한다. 예를 들어 도움말 페이지는 갱신할 필요가 없다. 따라서 Stateless Widget은 한 번 만들어지면 갱신할 수 없으므로 생명주기가 없다.
반면 Stateful Widget은 내용을 갱신해야 할 필요가 있는 동적인 위젯이다. 앞서 말했듯이 프로필 관리 페이지라고 하면, 프로필이 바꾸었을 때 화면이 다시 갱신 되어야 한다.
이렇게 상태 연결에 따라 위젯을 구분한 이유는 무엇일까?
Stateful Widget은 상태가 변경되면 알맞은 처리를 수행해야하므로 항상 앱이 위젯의 상태를 감시하고 있어야 한다. 따라서 메모리나 CPU 등 자원을 많이 소비해야 한다. 하지만 Stateless Widtet은 화면을 갱신할 필요가 없으므로 앱이 위젯의 상태를 감시하고 있지 않아도 된다. 즉 최대한 효율적으로 자원을 사용하기 위해서 Stateless Widget과 Stateful Widget으로 구분되어 있는 것이다.
그럼 Stateful Widget에 대해 더 알아보자. Stateful Widget은 생명주기가 있다. <Do it! 플러터 앱 프로그래밍> 책에서는 이 생명주기를 10개로 나누었다.
호출 순서 | 생명주기 | 내용 |
1 | createState() | 처음 Stateful을 시작할 때 호출 |
2 | mounted == true | createState() 함수가 호출되면 mounted는 true |
3 | initState() | State에서 제일 먼저 실행되는 함수. State 생성 후 한 번만 호출 |
4 | didChangeDependencies() | initState() 호출 후에 호출되는 함수 |
5 | build() | 위젯을 렌더링하는 함수. 위젯을 반환 |
6 | didUpdateWidget() | 위젯을 변경해야 할 때 호출하는 함수 |
7 | setState() | 데이터가 변경되었음을 알리는 함수. 변경된 데이터를 UI에 적용하기 위해 필요 |
8 | deactivate() | State가 제거될 때 호출 |
9 | dispose() | State가 완전히 제거되었을 때 호출 |
10 | mounted == false | 모든 프로세서가 종료된 후 mounted가 false로 됨 |
(표 출처 - <Do it! 플러터 앱 프로그래밍> p.82 표 3-3)
예전에 개발하면서 위젯의 상태와 관련하여 겪었던 이슈를 해결방법과 함께 다시 정리해보았다.
문제점
설정화면에서 캐릭터 변경하기 아이콘을 누르면 캐릭터 변경하기 모달이 나온다. 변경 후 '저장하기'를 누르면, 모달이 닫히고 다시 설정페이지가 보이게 되는데, 이때 화면갱신이 되어있지 않았다. 따라서 변경된 캐릭터가 아니라 여전히 기존 캐릭터로 프로필이 보이는 문제가 있었다.
문제원인
플러터에서 특정 작업을 수행한 뒤 화면을 갱신하려면 직접 setState를 호출해서 다시 위젯을 rebuild해야한다. setState 메서드는 데이터가 변경되었음을 프레임워크에 알리고 build context의 위젯을 다시 빌드하게 된다. 플러터 프레임워크 자체적으로도, 개발자에 의해서도 매우 자주 호출되는 메서드이다.
해결
기존에는 SvgImage를 불러올 때 widget.loginInfo.user.profile을 이용하여 loginInfo 내의 변화된 값으로 불러왔었는데, currentIndex라는 변수를 추가적으로 사용하여 상태변화를 명시적으로 드러내었다. 이를 setState 함수 안에 변화된 변수가 있음을 위의 이미지처럼 나타내면 플러터가 변화를 감지하고 화면을 갱신한다. _displayProfileSheet를 호출한 후에 .then을 이용해서 setState를 호출했다.
Stateful 위젯의 생명주기에 이렇게 많은 단계가 있는지 몰랐다. mounted==true나 didChangeDependencies() 함수 등 예전에는 처리를 안해주고 그냥 넘어갔던 부분도 많은 것 같다. 각 함수의 기능에 대해 짚고 넘어갈 수 있었고 예전에 개발하다 발생했던 관련 이슈도 다시 짚어볼 수 있어서 좋았다.