Search

Lifecycle Management

Created
2020/08/05
tag
Flutter
Lifecycle Management
어플을 만들다보면 Foreground에서 Background로 전환되었을 때, Background에서 다시 Foreground로 돌아왔을 때, 어플이 종료되었을 때 등 여러 상황에 대해 Lifcycle을 어플이 감지할 수 있도록 해야 각 상태 별로 로직 처리가 가능하다.

1. Lifecycle on StatefulWidget

Flutter에서 StatefulWidgetLifecycle은 (StatelessWidget 아님!) 아래와 같다.

1) createState()

StatefulWidget이 생성될 때 가장 먼저 호출되어 State를 생성하게 된다. State를 생성하면서 BuildContextState에 할당하게 된다.(필수적으로 Override를 해줘야 한다.)

2) mounted is true

Widget을 생성하면서 createState 함수를 통해 State가 생성되어 BuildContextState에 할당되었다면, Widget Tree에 해당 Widget을 위치시키게 된다. 사실 모든 Widget에는 bool 타입의 mounted라는 속성이 있는데, BuildContextWidget에 할당되면 mounted 값은 true가 할당된다. (추가로 unmountedWidget에 대해서 setState 함수를 호출했을 때는 에러가 발생한다.)

3) initState()

AndroidonCreate 함수 혹은 iOSviewDidLoad 함수와 동일하다.

4) didChangeDependencies()

initState 함수 호출 직후에 호출되며 setState 함수와 같이 build 함수를 재호출 하는 경우에도 build 함수 직전에 호출된다.

5) build()

GUI에 대해서 작성한 코드들이 Render된다.

6) didUpdateWidget()

Parent Widget이 바뀌면서 현재 Widget에 대해서 UI를 다시 Render해야할 때 호출된다.

7) deactivate()

Widget Tree에서 Flutter 프레임워크가 현 WidgetState를 삭제하려고 할 때 호출된다.

8) dispose()

Widget Tree에서 현 WidgetWidgetState가 완전히 삭제되어 다시 build 되지 않게 되었을 때 호출된다.

9) mounted is false

Widget Tree에서 해당 Widget이 삭제되면서 mounted 값은 false가 된다. 폐기된 State는 다시 생성되지 않는 이상 remount될 수 없다. 따라서 WidgetState에서 mounted 값이 false가 되었을 때는 setState 함수를 호출 시 에러가 발생하게 된다.

2. Lifecycle Management

위의 Lifecycle을 이용하면 현재 WidgetState에 따라서 로직을 처리할 수는 있지만, 어플리케이션의 Lifecycle 처리에는 어려움이 있다.
어플리케이션의 Lifecycle에 대해서 처리하기 위해선 Flutter에서 지원하는 WidgetsBindingObserver라는 클래스를 활용하면 된다. WidgetsBindingObserver 클래스에선 어플리케이션의 LifecycleAppLifecycleState로 두고 처리하고 있다. AppLifecycleStateenum이며, 내부에는 resumed, inactive, paused, detached와 같이 4가지 State가 있는 것을 확인할 수 있다. Flutter에서 처리하는 어플리케이션의 Lifecycleenum 타입의 AppLifecycleStat 내에 존재하는 4개의 값이 갖는 이름의 의미대로 처리하게 되며, 이를 통해 각 Lifecycle 별로 로직을 수행하도록 만들 수 있다.
WidgetsBindingObserver 클래스는 상속을 받아서 이용할 수도 있지만, StatefulWidget을 상속 받아 WidgetLifecycle 별로 로직을 처리함과 동시에 childMaterialApp 두어 어플 자체를 감시하도록 두는 경우에는 WidgetsBindingObserver 클래스를 Mixin으로 이용하도록 한다.
이 때 initState에서는 WidgetsBinding의 인스턴스에 Observer를 추가하고, dispose에서 WidgetsBinding의 인스턴스에 Observer를 삭제하도록 작성한다.
또한 어플리케이션의 Lifecycle이 변할 때마다 호출되는 didChangeAppLifecycleState에서 AppLifecycleState에 따라서 로직을 처리하도록 작성한다.
class LifecycleObserver extends StatefulWidget { _LifecycleObserverState createState() => _LifecycleObserverState(); } class _LifecycleObserverState extends State<LifecycleObserver> with WidgetsBindingObserver { void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); } void dispose() { WidgetsBinding.instance.removeObserver(this); super.dispose(); } void didChangeAppLifecycleState(AppLifecycleState state) { switch (state) { case AppLifecycleState.inactive: print('inactive -> $state'); // 로직 작성 break; case AppLifecycleState.paused: print('paused -> $state'); // 로직 작성 break; case AppLifecycleState.resumed: print('resumed -> $state'); // 로직 작성 break; case AppLifecycleState.detached: print('detached -> $state'); // 로직 작성 break; } super.didChangeAppLifecycleState(state); } Widget build(BuildContext context) { return MaterialApp( // MaterialApp Constructor 호출 ); } }
Dart
이렇게 어플리케이션의 Lifecycle을 처리할 수 있는데, 실제로 WidgetsBindingObserver 클래스를 까보면 didPopRoute 함수, didChangeLocales 함수, didChangeMetrics 함수, didChangeTextScaleFactor 함수 등을 찾아볼 수 있다. 어플리케이션 세팅의 전반적인 것들의 변화를 처리할 수 있는 것을 확인할 수 있다.

3. Reference