Flutter 앱 라이프사이클에 대해 설명해주세요

질문

Flutter 앱 라이프사이클에 대해 설명해주세요.

답변

Flutter 앱 라이프사이클은 앱이 시작되고, 실행되며, 종료되는 과정에서 거치는 여러 상태와 이벤트를 의미합니다. Flutter에서는 크게 두 가지 수준의 라이프사이클이 있습니다: 앱 수준 라이프사이클과 위젯 수준 라이프사이클입니다.

1. 앱 수준 라이프사이클

앱 수준 라이프사이클은 WidgetsBindingObserver를 통해 관찰할 수 있으며, 앱이 전체적으로 경험하는 상태 변화를 나타냅니다.

앱 라이프사이클 상태

AppLifecycleState 열거형은 다음 상태들을 정의합니다:

  1. detached: 앱이 플랫폼 뷰에 연결되지 않은 상태입니다. 주로 앱이 시작되기 전이나 종료된 후에 발생합니다.

  2. inactive: 앱이 시각적으로 보이지만 사용자 입력을 받지 않는 상태입니다. iOS에서는 앱 전환기를 열 때, 전화가 오거나 다른 시스템 알림이 뜰 때 발생합니다. Android에서는 이 상태가 거의 발생하지 않습니다.

  3. paused: 앱이 현재 보이지 않고, 사용자 입력을 받지 않으며, 백그라운드에서 실행 중인 상태입니다. 사용자가 다른 앱으로 전환했거나 홈 화면으로 갔을 때 발생합니다.

  4. resumed: 앱이 보이고 사용자 입력에 응답하는 상태입니다. 앱이 포그라운드에서 완전히 활성화된 상태입니다.

  5. hidden: Flutter 3.13부터 추가된 상태로, 앱이 시스템 네비게이션에 가려져 완전히 보이지 않지만 여전히 활성 상태인 경우입니다.

앱 라이프사이클 감지 방법

WidgetsBindingObserver를 구현하고 didChangeAppLifecycleState 메서드를 오버라이드하여 앱 라이프사이클 변화를 감지할 수 있습니다:

class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    switch (state) {
      case AppLifecycleState.resumed:
        print("앱이 포그라운드에 있고 사용자 입력을 받고 있습니다.");
        break;
      case AppLifecycleState.inactive:
        print("앱이 활성 상태가 아니고 사용자 입력을 받지 않습니다.");
        break;
      case AppLifecycleState.paused:
        print("앱이 현재 사용자에게 보이지 않고, 백그라운드에서 실행 중입니다.");
        break;
      case AppLifecycleState.detached:
        print("앱이 호스트 뷰에서 분리되었지만 플러터 엔진은 계속 실행 중입니다.");
        break;
      case AppLifecycleState.hidden:
        print("앱이 시스템 네비게이션에 가려져 있습니다.");
        break;
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(...);
  }
}

2. 위젯 수준 라이프사이클

위젯 수준 라이프사이클은 개별 위젯(특히 Stateful 위젯)의 생성, 업데이트, 제거 과정을 다룹니다.

StatefulWidget 라이프사이클

  1. createState(): StatefulWidget이 생성될 때 호출되며, 연결된 State 객체를 생성합니다.
  2. initState(): State 객체가 트리에 삽입될 때 한 번만 호출됩니다. 이곳에서 초기화 작업을 수행합니다.
  3. didChangeDependencies(): initState() 후에 호출되며, 위젯이 의존하는 InheritedWidget이 변경될 때마다 호출됩니다.
  4. build(): 위젯의 UI를 구성합니다. 이 메서드는 initState() 후, didUpdateWidget() 후, setState()가 호출된 후, 또는 의존성이 변경될 때마다 호출됩니다.
  5. didUpdateWidget(): 부모 위젯이 재구성되어 이 위젯을 새 위젯으로 업데이트할 때 호출됩니다(같은 runtimeType과 key를 가진 경우).
  6. setState(): 위젯의 내부 상태가 변경될 때 호출되어 Flutter에게 위젯을 다시 빌드하도록 알립니다.
  7. deactivate(): State 객체가 위젯 트리에서 일시적으로 제거될 때 호출됩니다. 위젯이 트리에서 이동할 때 발생할 수 있습니다.
  8. dispose(): State 객체가 위젯 트리에서 영구적으로 제거될 때 호출됩니다. 리소스를 해제하는 코드를 여기에 작성합니다.
class MyWidget extends StatefulWidget {
  @override
  _MyWidgetState createState() => _MyWidgetState(); // 1. createState
}

class _MyWidgetState extends State<MyWidget> {
  @override
  void initState() {  // 2. initState
    super.initState();
    print("initState 호출");
  }

  @override
  void didChangeDependencies() {  // 3. didChangeDependencies
    super.didChangeDependencies();
    print("didChangeDependencies 호출");
  }

  @override
  Widget build(BuildContext context) {  // 4. build
    print("build 호출");
    return Container();
  }

  @override
  void didUpdateWidget(MyWidget oldWidget) {  // 5. didUpdateWidget
    super.didUpdateWidget(oldWidget);
    print("didUpdateWidget 호출");
  }

  @override
  void deactivate() {  // 7. deactivate
    print("deactivate 호출");
    super.deactivate();
  }

  @override
  void dispose() {  // 8. dispose
    print("dispose 호출");
    super.dispose();
  }
}

3. 라이프사이클 활용 사례

백그라운드/포그라운드 전환 처리

@override
void didChangeAppLifecycleState(AppLifecycleState state) {
  if (state == AppLifecycleState.paused) {
    // 앱이 백그라운드로 갈 때 데이터 저장
    saveUserData();
  } else if (state == AppLifecycleState.resumed) {
    // 앱이 포그라운드로 돌아올 때 데이터 새로고침
    refreshData();
  }
}

리소스 관리

@override
void initState() {
  super.initState();
  // 위젯 생성 시 리소스 초기화
  videoController = VideoPlayerController.network('...')..initialize();
}

@override
void dispose() {
  // 위젯 제거 시 리소스 해제
  videoController.dispose();
  super.dispose();
}

상태 관리

@override
void didUpdateWidget(OldWidget oldWidget) {
  super.didUpdateWidget(oldWidget);
  if (widget.someProperty != oldWidget.someProperty) {
    // 속성이 변경되었을 때 상태 업데이트
    _updateInternalState();
  }
}

요약

Flutter 앱 라이프사이클은 앱의 상태 변화와 위젯의 생명주기를 이해하고 관리하는 데 중요합니다. 앱 수준 라이프사이클은 앱의 전체적인 상태(resumed, paused, inactive 등)를 다루고, 위젯 수준 라이프사이클은 개별 위젯의 생성부터 제거까지의 과정을 관리합니다. 이러한 라이프사이클 이벤트를 적절히 활용하면 리소스 관리, 상태 보존, 앱 성능 최적화 등을 효과적으로 수행할 수 있습니다.

results matching ""

    No results matching ""