[Android] Activity 살펴보기 : Activity 의 이해

12 분 소요

Activity 의 이해

우리가 안드로이드 앱을 개발하기 위해서는 흔히 4대 component 라고 불리는 Activity, Service, Broadcast Receiver, Contents Provider 가 필요합니다. 그 중에서 특히 Activity 를 제외한 나머지 컴포넌트들은 요구사항에 따라 추가하면 되지만 Activity 는 반드시 필요한 component 입니다.

Activity 는 android.app 에 있으며, ContextThemeWrapper 를 상속하고 여러 기능을 담당하기 위해 인터페이스들을 구현하고 있습니다. 그중에서 눈에 띄는 녀석은 Window 와 관련된 인터페이스들 입니다.

View #1 Android Ui 에도 한번 언급했듯이, Activity 는 Window 를 제공하고 있습니다. Window 는 앱의 도화지 역할을 하며, 개발자가 정의한 View 를 보여주기 위해 반드시 필요한 클래스입니다.

그밖에도 사용자와 앱간의 상호작용을 위한 여러 기능들을 제공해주고 있습니다. 안드로이드 공식 문서 에서 중요한 몇가지 기능들을 소개하고 있습니다. 그중에서 대표적인 몇가지를 보자면,

  1. Activity Lifecycle
  2. Task 와 Backstacks
  3. 상태 관리 솔루션
  4. 화면 또는 권한 요청과 결과 응답
  5. 프로세스 수명주기

주요 기능들을 먼저 살펴본뒤에, 내부코드를 보면서 이해를 해보는 순서로 가져가보겠습니다.

Activity Lifecycle

Activity 가 실행되는 진입점은 두가지로 분류됩니다.

첫번째는 project/app/manifest.xml 파일이 packageManager 에 의해 parsing 되고 난 뒤 앱런처 라는 앱에서 디바이스에 설치되어진 앱들이 노출되게 됩니다. 노출된 앱을 사용자의 상호작용에 의해 앱런처에서 앱이 실행(launch)되면서, manifest.xml 에서 intent-filter 로 action.MAIN 과 category.LAUNCHER 로 정의된 Activity 가 ActivityThread 의 main() 함수 내부에서 launch 되어집니다. 한가지 더 생각해보자면, 해당 Activity 를 외부(런처앱)에서 실행할 수 있어야 하기 때문에 manifest.xml 에서 Activity 태그에 exported = true 를 해둔다는 점입니다. 이것을 false 로 하면 앱 외부에서 실행할 수 없습니다.

두번째는 실행된 앱 프로세스 내에서 화면 요청 과정인 ContextWrapper#startActivity() 를 실행하여 Instrumentation#execStartActivity() 에 의해 activity thread 로 dispatch 되면 Activity 가 launch 됩니다.

두가지 방식 모두 ActivityThread 에 의해서 launch 과정이 수행되고 궁극적으로는 Instrumentation 에 의해서 인스턴스화 한 뒤 순서대로 정의된 콜백 메소드를 실행하게 됩니다.

activity_lifecycle

콜백 메소드들을 하나씩 살펴보겠습니다.

Callbacks

onCreate()

Activity 생성 이후 가장 먼저 호출되는 콜백입니다. Activity 가 인스턴스화 된 후 부터 단 한번만 실행 되므로, 필요한 인스턴스들의 초기화와 같은 작업들을 이곳에서 수행해야 합니다.

파라미터로 전달되는 savedInstanceState bundle 객체는 상태 복원의 용도로 제공됩니다. 해당 값은 nullable 하며 복원할 상태가 없다면 null 이 전달됩니다.

중요한점은, 개발자가 정의한 뷰를 이곳에서 인스턴스화 한 뒤 Activity의 window 인스턴스에 존재하는 mContentparent 로 할당하는 뷰 연결 작업 을 수행해주어야 합니다. 이것을 수행하는 메소드는 xml 방식의 경우 Activity#setContentView() 혹은 compose 방식의 경우 ComponentActivity#setContent() 를 이용하시면 됩니다. 해당 내용은 View #1 Android Ui 포스팅에서 이미 다룬 내용이기도 합니다.

마지막으로 onCreate() 호출 이전에 Activity 가 인스턴스화 된 경우 Lifecycle State 는 INITALIZED 이고, onCreate() 가 호출된 후에 시스템은 ON_CREATE 이벤트를 호출하게 되고 Lifecycle State 는 CREATED 가 됩니다.

onStart()

onCreate() 가 호출된 직후 onStart() 가 실행됩니다. onStart()가 호출되면서 Activity 가 화면에 보여지기 시작합니다. 따라서 실행중인 앱의 프로세스 상태는 Visible 이 됩니다.

onStart() 호출 후 시스템은 ON_START 이벤트를 호출하게 되고 Lifecycle State 는 CREATED -> STARTED 가 됩니다.

onRestoreInstanceState()

onRestoreInstanceState(Bundle) 는 저장된 상태가 있는 경우 복원할 목적으로 실행되는 콜백입니다. 매개변수로 전달받는 bundle 객체는 non-null 하며, onSaveInstanceState() 가 실행되었더라도 상태를 복원할 필요가 없다면 onRestoreInstanceState() 는 실행되지 않습니다.

개발자에 의해 Activity 에서 사용하는 상태들이 복원되기도 하지만, 시스템에 의해 관리되는 backstack 이나 viewtree 정보들도 마찬가지로 내부 코드로 저장 및 복원됩니다. 따라서 개발자가 직접 코드 작업하지 않아도 view-tree 에 존재하는 scrollView 의 스크롤 위치나, EditTextView 에 있었던 text 값들 등이 android:id 태그 값이 할당되어 있다면 자동으로 저장 및 복원됩니다.

onResume()

onResume()이 호출되면, Activity 의 window 의 mContentParent 에 연결된 화면이 보여집니다. 화면이 사용자에게 보여진다는 것은 다른말로 focused(포커스를 받고 있음) 라고 얘기하며, Focused Activity 는 backstack 의 top 에 있으며, 프로세스 상태가 Foreground 가 됩니다. Activity Backstack 에 관련해서는 후술할 예정입니다.

onResume() 호출 후 시스템은 ON_RESUME 이벤트를 호출하게 되고, Lifecycle State 는 RESUMED 가 됩니다.

onPause()

onPause()는 onResume() 에 대응되며, Activity 의 window 가 일부 가려지게 됬을 때 호출됩니다. 즉, Dialog 와 같은 다른 window 가 열리면서 해당 Activity 의 window가 가려지며, 반투명으로 흐려져 보이게 됩니다. 그와 동시에 Activity 는 focus 를 잃게 되며, 프로세스 상태는 Visible 이 됩니다.

아직은 Activity 의 window 가 일부 보여지고 있으므로, UI 의 update 가 가능합니다. 또한, 해당 callback 은 빠르게 지나가기 때문에 DB 트랜잭션이나 네트워크 호출과 같은 비동기로 처리해야하는 작업들을 이곳에서 처리하면 안됩니다.

onPause() 콜백부터는 onCreate() ~ onResume() 과 대응되는 즉, 반전 형태를 가집니다. onPause() 호출 전 시스템은 ON_PAUSE 이벤트를 먼저 호출하고, Lifecycle State 는 STARTED 가 됩니다. 이후 onPause() 콜백을 실행합니다. onPause() 호출 이후 Activity 가 재개되는 경우 onResume() 콜백을 호출합니다.

onStop()

onStop() 은 onStart() 와 대응되며, Activity 의 window 가 더이상 보이고 있지 않다는 것을 의미합니다. 보통 시스템의 home 버튼이나 back 버튼으로 Activity 에서 이탈하는 경우 발생하며, configuration change 에서도 발생합니다.

아직 Activity 의 인스턴스가 메모리에는 남아있지만, windowManager 와의 연결은 제거됩니다. 보통 해당 callback 에서 실행중인 작업을 종료 및 리소스를 제거 해야 합니다. 예를들면, 더 이상 화면이 보여지지 않기 때문에 보통 ViewModel 에서 가지는 UI 관련 상태들의 수집 또는 비동기 작업을 이 콜백에서 종료합니다.

home 버튼으로 앱에서 이탈 시, App 프로세스 상태는 background 가 됩니다.(주의하세요. Activity 전환의 경우 프로세스 상태는 background 로 바뀌지 않습니다.) 이러한 경우 후술할 예정이지만 시스템이 메모리 부족으로 인해 언제든지 프로세스를 종료할 수 있으며, Activity 가 메모리에서 제거될 수 있습니다. 따라서, 사용자 경험을 보완하기 위해 다른 포스팅에서 서술한 바와 같이 상태 관리 #2 SavedState 메커니즘을 제공하고 있습니다. 또한 backstack 역시 마찬가지로 해당 매커니즘으로 관리되어 메모리 부족으로 인해 시스템이 프로세스를 종료시켰더라도 최근 화면에서 다시 앱을 실행하면 이전 진행 흐름(Activity backstack)을 유지할 수 있습니다. 아래 Lifecycle Scenario 에서 더 자세히 다루겠습니다.

onStop() 호출 전 시스템은 ON_START 이벤트를 먼저 호출하고, Lifecycle State 는 CREATED 가 되며, 이후 onStop() 이 실행됩니다. 또한, onStop() 이후 다시 Activity 가 재개되는 경우 onRestart() 콜백을 호출합니다.

onSaveInstanceState()

상태 복원은 시스템에 의해 프로세스가 메모리에서 제거되는 경우 사용자 경험을 보완하기 위해 이전까지의 실행 흐름을 저장 및 복원하여 재개 시점부터 이어나갈 수 있도록 도와주기 위해 제공되는 매커니즘 입니다. 그중 onSaveInstanceState() 는 상태를 저장하기 위한 콜백으로 반드시 호출되는 콜백은 아닙니다.

onSaveInstanceState() 는 사용자가 명시적으로 Activity 를 이탈하는 경우에 대해서는 호출되지 않습니다.(자세히는 onFinish() 를 호출한 경우) 앱이 정상적으로 종료된 경우 상태를 저장 및 복원할 필요가 없기 때문입니다. 즉, onSaveInstanceState() 는 다른 화면으로의 전환이나 시스템의 home 버튼에 의해 잠시 Activity 를 이탈한 경우, 마지막으로 configuration change 가 발생한 경우 onStop() 이후에 호출됩니다.

매개변수로 전달받는 bundle 객체에 상태를 저장해주면, 이에 대응되는 콜백인 onRestoreInstanceState(Bundle) 나 onCreate(Bundle) 콜백에 매개변수로 전달받는 bundle 객체로 복원하실 수 있습니다.

onDestroy()

onDestroy() 는 onCreate() 와 대응되며, Activity 가 더 이상 유효하지 않아 메모리에서 제거되기 직전에 호출되는 콜백입니다. onStop() 까지는 화면 전환이나 시스템 UI 의 home 버튼을 눌러 잠깐 Activity 를 이탈했을 때 호출되지만, 사용자가 앱의 backstack 의 마지막 Actvitiy 를 back 버튼으로 이탈하여 onFinish() 가 호출되거나 configuration change 로 인해 메모리에서 제거될 때 onDestroy() 가 호출될 수 있습니다. 따라서 메모리에서 제거되기 직전이므로 onStop() 에서 정리하지 않은 리소스를 반드시 여기서 제거해야 합니다. 그렇지 않으면 메모리 누수의 원인이 될 수 있습니다.

앱의 backstack 에서 마지막 Activity 가 제거되는 경우 앱 프로세스 상태는 EMPTY 가 됩니다. onDestroy() 호출 전 시스템은 ON_DESTROY 이벤트를 먼저 호출하고, Lifecycle State 는 DESTROYED 가 되며, 이후 onDestroy() 콜백이 실행됩니다.

lifecycle_state

이미 위에서 서술했듯이 lifecycle 관련 callback 실행은 전후에 시스템에서 특정 event 들을 실행합니다. 따라서 LifecycleOwner 구현체로부터 lifecycle 을 얻을 수 있다면, observer 패턴으로 callback 을 등록하여 lifecycle-aware 하게 특정 동작을 실행시킬 수 있습니다. 가장 흔한 예시로 androidx.lifecycle 의 repeatOnLifecycle() 확장 메소드는 Activity 또는 Fragment 에서 화면이 보이지 않는 경우 ViewModel 에서 수집하는 UI 관련 상태의 수집을 중지시키기 위한 용도로 만들어졌습니다.


lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
    uiStateFlow.collect { uiState ->
    updateUi(uiState)
    }
  }
}

Lifecycle Scenario

해당 포스팅에서는 더 자세한 Activity 의 Lifecycle 을 알아보기 위해 몇가지 시나리오를 예시로 다뤄보려 합니다.

Single Activity

Activity 가 단 하나만 존재하는 경우에 대해 몇가지 시나리오를 더 자세히 살펴보겠습니다.

  • 시스템 back 버튼을 누르거나 onFinish() 를 명시적으로 호출한 경우

Activity 가 onPause() ~ onDestroy() 까지 연속적으로 호출됩니다. 즉, Activity 가 메모리에서 제거됩니다. 하지만 onSaveInstanceState() 는 호출되지 않습니다. Backstack 에 하나의 Activity 만 존재했다면, 앱 프로세스 상태는 EMPTY 가 됩니다.

  • Configuration Change 가 발생한 경우

Activity 가 onPause() - onStop() - onSaveInstanceState(bundle) - onDestroy() 까지 연속적으로 호출 된 후, 즉시 onCreate(bundle) - onStart() - onRestoreInstanceState(bundle) - onResume() 까지 호출됩니다. 위에서 설명한 바와 같이 이 때의 onCreate 의 bundle 파라미터는 null 이 아닙니다.

  • Dialog 와 같이 다른 window 에 의해 일부가 가려진 경우

Activity 가 onPause() 까지 호출되면서 포커스를 잃고 반투명 으로 보여지게 됩니다. 다른 window 가 제거되는 경우 다시 onResume() 이 호출되며 재개됩니다.

  • 다른 앱으로 전환되는 경우

Notification 을 클릭하거나 최근 화면에서 다른앱을 클릭하여 전환되는 경우 Activity 가 onPause() - onStop() - onSaveInstanceState(bundle) 까지 연속적으로 호출되고, 앱 프로세스가 background 로 전환됩니다. Background 상태인 앱 프로세스는 언제든지 메모리가 부족할 때 시스템에 의해 제거되어질 수 있기 때문에 상태 저장 및 복원을 위해 onSaveInstanceState 가 호출되어집니다.

이후 다시 원래 앱으로 돌아간다면 onRestart() - onStart() - onRestoreInstanceState(bundle) - onResume() 순서로 재개됩니다. onStop() 까지 호출되었다면 onStart() 가 아닌 onReStart() 부터 시작한다는 점이 다릅니다. 또한 만약, 앱 프로세스가 시스템에 의해 메모리에서 제거되었다면 onCreate(bundle) - onStart() - onRestoreInstanceState(bundle) - onResume() 순서로 재개됩니다. 여기서 알 수 있는 점은 시스템에 의해 제거된다면 onDestroy() 콜백은 실행되지 않는다는 것입니다. 만약, 특정 컴포넌트 또는 앱이 종료되었는지를 판단하기 위해 onDestroy() 콜백을 이용한다면 정상적으로 확인할 수 없을것입니다.

Mutli Activity

Activity 가 하나일 때와 두개일 때는 큰 차이는 없습니다. 위의 4가지 시나리오에서 두개의 Activity 간의 전환이 된 경우가 추가됬을 뿐입니다.

  • Activity a 에서 b 로의 전환 후 시스템 back 버튼을 누르거나 onFinish() 를 명시적으로 호출한 경우

Activity a 의 onCreate - onStart - onResume 이 호출된 상태에서 b 로의 전환이 일어나면 a 는 onPause - onStop - onSaveInstanceState 까지 호출되며, 동시에 b는 onCreate - onStart - onResume 이 호출됩니다. 두개의 activity 의 lifecycle callback 호출은 병렬로 수행되어, 두 그룹간에 스위칭 될 수 있습니다. 다만, 한 액티비티내의 순서는 보장됩니다.(정확히는 a 액티비티의 onPause() 호출 후, b 액티비티의 onCreate - onStart - onResume 호출 후, a 액티비티의 onStop 이 호출됩니다.) 또한, a 액티비티 는 backstack 에 쌓이게 되고 메모리에서 제거된 것이 아닙니다. b 액티비티에서 back 버튼 혹은 onFinish() 가 호출된다면 b 액티비티는 명시적으로 종료되기 때문에 onPause - onStop - onDestroy 가 호출되고 제거되며, 동시에 a 는 onRestart - onStart - onResume 이 호출됩니다. a 의 경우 메모리에서 제거되지 않았기 때문에 상태는 저장했지만 복원할 필요가 없으므로 onRestoreInstanceState() 가 호출되지 않습니다.

  • 만약 Activity a -> b 로 전환 후, 다른앱 으로 전환했다면?

위의 콜백 호출에서 볼 수 있듯이 b 로 전환할 때 시스템에 의해 종료될 경우를 대비하기 때문에 a 액티비티가 포커스를 잃으면서 onSaveInstanceState() 까지 호출됩니다. 마찬가지로 다른앱으로 전환 하면서 b 액티비티는 onPause - onStop - onSaveInstanceState 까지 호출됩니다.

  • a -> b 로 전환한 상태에서 메모리 부족 등으로 인해 시스템에 의해 프로세스가 종료되고 다시 앱프로세스를 실행했다면?

상태를 저장했기 때문에 backstack 이나 view 계층구조 모두 복원되어 이전의 흐름에서 그대로 재개할 수 있습니다. 단지 두 Activity 모두 메모리에서 제거되었기 때문에 다시 앱 프로세스를 실행했을 때 Activity b 가 onCreate - onStart - onRestoreInstanceState - onResume 이 호출되며, b 에서 a 로 되돌아간다면 b 는 onPause - onStop - onDestroy 가 호출되며 Activity a 는 onCreate - onStart - onRestoreInstanceState - onResume 이 호출됩니다.

  • a -> b 로 전환한 상태에서 configuration change 가 발생했다면?

Activity b 가 onPause - onStop - onSaveInstanceState - onDestroy 까지 호출된 후 즉시 onCreate - onStart - onRestoreInstanceState - onResume 이 호출됩니다. 즉 위에서 다룬 콜백이 그대로 실행됩니다. 이후 b 에서 a 로 되돌아간다면, Activity b 는 onPause - onStop - onDestroy 가 호출되며 Activity a 는 onCreate - onStart - onRestoreInstanceState - onResume 이 호출되게 됩니다.

뭔가 특이점이 느껴지셨나요? 맞습니다. 특정 상황에서의 lifecycle 변화가 focus 를 받고 있는 Activity 에서 일어난다는 점입니다. 이 규칙으로 이해하신다면, 별도로 해당 상황들에 대한 lifecycle 변화를 외울 필요없이 떠올리실 수 있을겁니다.

Task 와 backstack

Task 란 안드로이드에서 A task is a collection of activities that users interact with when trying to do something in your app. 라고 정의하고 있습니다. 즉, activity들을 유지하는 collection 입니다. 하지만 여러 activity 를 전환하면서 단순히 collection 으로 그 순서를 유지하기는 어렵습니다. 따라서 backstack 이라고 불리는 stack 구조의 LIFO 자료구조를 사용하여 activity 들의 순서를 유지합니다. 요약하자면, Task 에는 backstack 이라 불리는 스택 자료구조로 Activity 들을 가지고 있습니다.

Task 와 Process 의 개념은 다릅니다. Process 개념은 안드로이드 프레임워크가 Linux 기반이기 때문에 Linux 의 프로세스 개념과 같습니다. 하지만, Task 는 Activity 에 대한 메모리를 저장하고 있는 단위로 안드로이드에서 만들어진 개념입니다.

조금더 예시를 들어볼까요? 개발자가 만든 앱 A 의 Activity A1 에서 다른 앱 B 의 Activity B1 를 요청해서 어떤 결과값을 가져온다고 생각해 봅시다. B 앱에서 딥링크를 처리하고 호출가능하도록 exported = true 로 뒀다고 가정해봅시다. 그러면 프로세스 관점에서는 앱A 는 background 이고 앱B 는 Foreground 일것입니다. 하지만, Task 에서는 A1 과 B1 이 차례로 쌓여있을 것입니다.(여기서 B1 의 launchMode 를 standard 로 가정합니다.) 어떻게 다른 앱이 현재 Task 에 쌓일 수 있을까요? 실제로 Activity 는 Java Api Framework 의 SystemServer 로 분류되는 ActivityManagerService 에 의해 관리됩니다. 이를 이용한 Task 개념에서는 프로세스가 다르더라도 Activity 관점에서 바라보기 때문에 가능한 것 입니다.

런처앱 에서 앱을 실행했을 때 task 가 존재하지 않는다면, task 를 생성한 뒤 manifest 에 정의된 Launcher Activity 를 실행하게 됩니다. 하지만 개발자는 필요로 인해 task 가 있는 상태에서 다른 task 로 activity 를 실행하거나, 같은 task 안에서 같은 activity 를 재사용 하고 싶을 수 있습니다.(같은 task 안에서 default 로 같은 activity 를 두번 실행하면, backstack 에 호출 순서대로 두개가 쌓이게 됩니다.)

이를 위해 manifest 에서 activity 의 launchMode 태그로 실행 방법에 대해 명시할 수 있습니다.

  1. standard : default 모드 입니다. 호출 순서대로 backstack 에 무조건 쌓입니다. 즉, 같은 activity 가 여러번 호출되면 여러번 인스턴스화 하고 쌓입니다.
  2. singleTop : 만약, backStack 의 Top 에 호출하는 Activity 가 있다면, 재사용하고 onNewIntent() 를 호출합니다. 그렇지 않다면 standard 와 동일하게 실행됩니다.
  3. singleTask : taskAffinity(task 를 분류하는 단위) 가 같은 기존 task 에서 같은 activity 가 있는지 찾아 있으면, 새로운 태스크로 분리하여 재사용 하고 onNewIntent() 를 호출합니다. 이 때, task 의 backstack 에서 해당 activity 위에 존재하는 모든 activity는 소멸됩니다. 없다면, 새로운 task 에 root activity 로 만들어 실행합니다.
  4. singleInstance : Task 에는 하나의 activity 만 존재할 수 있습니다. activity 호출은 task 생성을 동반합니다.
  5. singleInstancePerTask : singleInstance 와는 달리 task 내에 다른 activity 는 실행될 수 있습니다.

보통의 앱에서는 standard 나 singleTop 으로도 충분할 것입니다. 필요에 따라 적절하게 사용하면 됩니다.

launchMode 태그 이외에도 Activity 실행시에 intent 로 flag 를 설정할 수도 있습니다.

  1. FLAG_ACTIVITY_NEW_TASK : launch mode 의 singleTask 와 동일하게 실행됩니다.
  2. FLAG_ACTIVITY_SINGLE_TOP : launch mode 의 singleTop 과 동일하게 실행됩니다.
  3. FLAG_ACTIVITY_CLEAR_TOP : 실행하는 Activity 가 이미 task 에 존재한다면, 재사용 하고 그위에 존재하는 모든 activity 를 소멸시킵니다. 따라서 실행하는 Activity 가 backstack 의 top 이 됩니다.

Intent 로 설정된 flag 는 launchMode 보다 높은 우선순위를 가집니다.

상태 관리

상태 관리 솔루션의 경우 이미 안드로이드 상태 관리 에서 다루었습니다. 해당 내용들은 1~3 로 3개의 챕터로 자세히 소개하고 있으니 생략하겠습니다.

화면 또는 권한 요청과 응답 처리

화면요청은 Api 30 미만에서는 contextWrapper#startActivity() 또는 Activity#startActivityForResult() 로 응답 처리가 가능합니다. 또한, 권한은 ActivityCompat#requestPermissions() 로 요청하고, Activity#onRequestPermission() 에서 응답을 처리할 수 있습니다.

API 30 이상에서는 ActivityResult*** 로 화면 또는 권한을 요청하고 callback 으로 응답을 처리합니다. 해당 자세한 내용들은 ComponentActivity 챕터에서 다루도록 하겠습니다.

프로세스 수명주기

프로세스 수명주기는 공식문서 에 자세히 설명되어 있습니다.

앱에서 사용자와 상호작용 하고 있는 Activity 가 존재하거나, BroadcastReceiver.onReceive() 가 실행중이거나, Service 의 수명주기 콜백이 실행중이라면 Foreground 상태로 유지됩니다. 그렇지 않은 경우 Visible 또는 background 에 위치할 수도 있습니다.

보통 앱의 비즈니스에 따라 background 에서 특정 작업을 수행할 필요가 있습니다. 음악 스트리밍 앱의 경우 다른앱 으로 전환하여 해당 앱이 보이지 않는 상태에서도 음악이 재생되어야 할 수도 있으며, 헬스 앱의 경우 앱이 보이지 않는 상태에서 걸음수를 수집해야 할 수도 있습니다.

안드로이드에서의 최근 업데이트 방향성은 background 작업에 대해 보안 및 사용자 경험 측면에서 개발자가 크게 사용하지 못하도록 제약을 추가하고 있습니다. 보통의 음악 스트리밍이나 헬스 데이터 앱은 ForegroundService 를 이용하여 Notification 을 통해 해당 앱이 보이지는 않지만 실행중임을 알려주도록 권고하고 있습니다. 그렇지 않은 경우 정해지지 않은 방식으로 background 에서 실행중인 앱은 동작하지 않거나 언제든지 시스템에 의해 종료될 수 있습니다. 또한 전원 관리에서 소개하는 앱 제한/대기/잠자기 모드 로 인해 background 작업에 대해 많은 제약이 존재합니다. 이에 대한 만병통치약은 ForegroundService 이지만 반드시 Notification 이 노출되어야 한다는 단점(?)도 존재하며 적절한 방법을 이용하여 안드로이드 환경에서의 요구를 충족시키는 앱을 개발하여야 합니다.

그외 자세한 설명은 공식문서를 보시길 권장드립니다.

태그:

카테고리:

업데이트:

댓글남기기