카테고리 없음

[세미나] 앱 라이프 사이클

파랑o 2023. 4. 13. 10:30

포그라운드(Foreground) & 백그라운드(Background)

기본 개념

 포그라운드와 백그라운드에 대해, 두 가지 관점에서 이야기 할 수 있습니다.

  1. 앱 상태에 따른 구분: 일반적으로, 화면에 보이는지 아니면 보이지 않는 상태에서 실행되고 있는지에 따라 각각 포그라운드와 백그라운드에 있다고 말합니다.
  2. 앱 내 특정 작업의 실행 환경에 따른 구분: 앱 자체는 포그라운드에 있더라도, 그 앱의 특정 작업은 백그라운드에서 실행된다고 말할 수 있습니다. 예를 들면, UI 관련 작업은 포그라운드에서, 데이터 처리는 백그라운드에서 실행될 수 있습니다.

앱의 상태(생명주기)

Android

앱(액티비티)의 실행 상태

  • onCreate(): 액티비티가 생성될 때 호출되며, 초기화 작업을 수행합니다.
  • onStart(): 액티비티가 사용자에게 보여지기 직전에 호출됩니다.
  • onResume(): 액티비티가 사용자와 상호작용하기 시작할 때 호출됩니다.
  • onPause(): 다른 액티비티가 화면을 가릴 때 호출되며, 일시적인 리소스를 해제하거나 저장하는 작업을 수행합니다.
  • onStop(): 액티비티가 완전히 가려졌을 때 호출되며, 필요한 경우 상태 저장을 수행합니다.
  • onRestart(): onStop() 이후에 액티비티가 다시 시작될 때 호출됩니다.
  • onDestroy(): 액티비티가 완전히 종료될 때 호출되며, 리소스 해제 작업을 수행합니다.

 

포그라운드 / 백그라운드 전환 시 발생하는 이벤트

  • 포그라운드 -> 백그라운드
    • Android: onPause(), onStop()
    • Flutter: ApplifecycleState.inactive, ApplifecycleState.paused
  • 백그라운드 -> 포그라운드
    • Android: onRestart(), onResume()
    • Flutter: ApplifecycleState.resumed

iOS

앱의 실행 상태

  • Not Running
    • 앱이 실행되기 전, 또는 종료된 상태입니다.
  • Foreground
    • 앱이 실행되어 사용자에게 보여지는 상태입니다.
    • 오직 하나의 앱만 포그라운드 상태를 가지며, 다시 inActive와 Active의 두 가지 상태로 나뉩니다.
      • inActive: 앱이 실행 중이며 포그라운드 상태에 있지만 이벤트는 받지 못하는 상태입니다. 앱이 처음 실행될 때, 전화가 왔을 때, 앱 스위처가 표시되고 있을 때 등이 해당됩니다.
      • Active: 앱이 실행 중이고, 포그라운드 상태에 있으며, 이벤트도 정상적으로 받을 수 있는 상태입니다. 사용자와 상호 작용 할 수 있는 상태입니다.
  • Background
    • 포그라운드 상태에서 홈화면으로 이동한 상태입니다.
    • 앱은 여전히 코드를 실행하고 있지만, 주 화면은 보이지 않는 상태입니다. 일시 중지 상태로 전환하기 전에 코드를 실행하는 경우입니다. 예를 들어, 음악 재생이나 위치 추적과 같은 작업을 수행할 때 백그라운드 상태에 머물게 됩니다.
    • 백그라운드 상태로 전환되기 전에 호출된 작업이 끝나지 않은 경우, 해당 작업은 백그라운드 상태에서도 여전히 실행됩니다.
    • 하지만, 백그라운드 상태로 실행 가능한 제한 시간이 존재하며, 그 이후에는 Suspended 상태로 넘어갑니다. 제한 시간은 시스템 리소스, 배터리 상태, 앱의 요구사항 등에 따라 결정됩니다.
    • 백그라운드 상태로 전환된 후 호출된 작업은 포그라운드 상태로 전환된 후에 실행됩니다.
  • Suspended
    • 앱이 백그라운드 상태로 전환된 이후, 더 이상 수행할 작업이 없으면 진입하는 상태입니다.
    • 앱은 메모리에는 여전히 존재하지만, CPU와 배터리 사용은 최소화 됩니다.
    • OS는 메모리가 부족할 때 suspended 상태의 앱을 종료시켜 메모리를 확보합니다.

포그라운드 / 백그라운드 전환 시 발생하는 이벤트

  • 포그라운드 -> 앱 스위처
    • iOS: applicationWillResignActive()
    • Flutter: ApplifecycleState.inactive
  • 앱 스위처 -> 백그라운드
    • iOS: applicationDidEnterBackground()
    • Flutter: ApplifecycleState.paused
  • 앱 스위처 -> 앱 클릭
    • iOS: applicationWillEnterForeground()
    • Flutter: ApplifecycleState.inactive
  • 앱 스위처 -> 포그라운드
    • iOS: applicationDidBecomeActive()
    • Flutter: ApplifecycleState.resumed

백그라운드 작업 수행

Android

Service

 안드로이드에서는 서비스(Service)라는 것으로 사용자와 상호 작용이 필요없는 작업을 수행합니다. 여기서 서비스는 세 가지로 구분할 수 있습니다.

  • 포그라운드 서비스 (Foreground Service): 사용자에게 계속해서 알려야 하는 작업을 처리할 때 사용합니다. 따라서, 항상 알림을 통해 작업이 진행중임을 표시해야 합니다. 예를 들면, 우리 앱의 걸음 수 알림이나, 음악 앱의 음악 재생 등이 있습니다.
  • 백그라운드 서비스 (Background Service): 사용자에게 알릴 필요가 없는 작업을 처리할 때 사용합니다. 이에 따라, 따로 사용자에게 알림을 표시할 필요가 없습니다. 포그라운드 서비스에 비해 사용자로부터 숨겨져 있기에, OS는 시스템 리소스가 부족하면 강제로 종료시킬 수 있습니다. 백그라운드 서비스의 예로는, 파일 다운로드나 데이터 동기화 등이 있습니다.
  • 바인드 서비스 (Bind Service): 앱 내의 여러 액티비티들은 특정 서비스에 바인딩될 수 있고, 바인딩된 액티비티와 서비스는 마치 가각, 클라이언트와 서버 관계를 가지고 데이터를 주고받을 수 있습니다. 예를 들면 채팅앱에서, 채팅방에 해당하는 액티비티는 바인드 서비스에 연결되어 새로운 메시지를 제공받을 수 있습니다.

 적절하지 않은 서비스로 작업을 구현하면 원하지 않는 상황이 발생할 수 있습니다. 예를 들어, 음악 재생 기능을 포그라운드 서비스가 아닌 백그라운드 서비스로 구현하게 되면, 시스템 리소스가 부족할 때 서비스가 종료되어 음악이 끊기는 현상이 발생할 수 있습니다. 반대로, 백그라운드 서비스로 구현해도 무리가 없는 데이터 동기화와 같은 작업을 포그라운드 서비스로 구현할 경우, 사용자는 보고싶지 않은 알림을 계속해서 보게 될 것 입니다.

관련 규칙

 안드로이드 문서에 따르면, 앱이 포그라운드에 있는 상황에는 백그라운드 실행 제한 규칙이 적용되지 않습니다. 안드로이드 OS가 앱이 포그라운드에 있다고 간주하는 경우는 아래과 같습니다. 아래 세 가지 항목에 포함되지 않는 상태일 경우, 백그라운드에 있다고 간주합니다.

  • 화면에 보이는 액티비티가 있는 경우
  • 포그라운드 서비스가 있는 경우
  • 다른 포그라운드 상태의 앱이, 현재 앱의 서비스에 바인딩되어 있는 경우 (ex. 입력기, 배경화면 서비스, 알림 리스너, 음성/텍스트 서비스 등)

 앱이 백그라운드 상태가 되어도, 몇 분간은 앱이 서비스를 생성하고 사용하는 것이 여전히 허용됩니다. 이 기간이 끝나면 앱은 유휴 상태로 간주되고, OS는 앱의 백그라운드 서비스를 중지시킵니다.

 다만, 특정 상황에서는 백그라운드 앱이 일정 기간 동안 임시 허용 목록에 들어가기도 합니다. 허용 목록에 있는 동안에는 백그라운드 서비스를 비롯한 다양한 서비스를 시작할 수 있습니다. 앱이 임시 허용 목록에 포함되는 경우는 아래와 같습니다.

  • 우선순위가 높은 FCM(Firebase Cloud Messaging) 메시지 처리를 수행하는 경우
  • SMS/MMS 메시지를 수신하는 경우
  • 알림을 통해, 지연된 작업을 실행하는 경우 (ex. 파일 다운로드 완료 알림 등)

iOS

관련 정책

  • 백그라운드에서 수행할 수 있는 작업 유형을 명시적으로 정의하고 있으며, Info.plist 파일에 사용하고자 하는 작업의 키 값을 추가해야 합니다. 오디오 재생, 위치 추적, VoIP, 뉴스피드 업데이트, 외부 액세서리와의 통신 등이 이에 해당합니다.
  • 오디오 재생이나 VoIP와 같은 작업은 알림을 표시해 사용자가 해당 작업이 실행 중임을 알 수 있어야 합니다.

Flutter

플러터에서 생명주기 이벤트 추적하기

WidgetsBindingObserver의 didChangeAppLifecycleState 함수 사용

 WidgetsBindingObserver 클래스의 구상 클래스는 didChangeAppLifecycleState 함수를 오버라이드 하여 아래의 네 종류의 이벤트를 추적할 수 있습니다.

  •  AppLifecycleState.resumed
    • 앱이 백그라운드에서 포그라운드로 전환되는 경우
    • Android의 onResume 메서드 호출 시, iOS의 active 상태로의 상태 전환 시
  • AppLifecycleState.inactive
    • 앱이 비활성 상태로 전환됨
    • Android의 onPause 메서드 호출 시, iOS의 inActive 상태로의 상태 전환 시
  • AppLifecycleState.paused
    • 앱이 포그라운드에서 백그라운드로 전환됨
    • Android의 onStop 메서드 호출 시, iOS의 background 상태로의 상태 전환 시
  • AppLifecycleState.detached
    • 앱이 종료됨
    • iOS에서만 발생

 앱의 시작과 종료 이벤트까지 추적하는 방법에는 StatefulWidget의 State 클래스 내부의 initState와 dispose 함수를 오버라이드하여 활용하는 방법이 있습니다.