활동 수명 주기

사용자가 앱을 탐색하고 앱에서 나갔다가 다시 돌아오면 앱의 Activity 인스턴스는 수명 주기에서 서로 다른 상태 간에 전환됩니다. Activity 클래스는 상태가 변경되거나 시스템이 활동을 생성, 중지 또는 재개하거나 활동이 있는 프로세스를 소멸시킬 때 활동에 알리는 여러 콜백을 제공합니다.

수명 주기 콜백 메서드 내에서 사용자가 활동을 떠났다가 다시 들어올 때 활동이 작동하는 방식을 선언할 수 있습니다. 예를 들어 스트리밍 동영상 플레이어를 빌드하는 경우 사용자가 다른 앱으로 전환할 때 동영상을 일시중지하고 네트워크 연결을 종료할 수 있습니다. 사용자가 돌아오면 네트워크에 다시 연결하고 사용자가 같은 지점에서 동영상을 다시 시작하도록 할 수 있습니다.

각 콜백을 사용하면 지정된 상태 변경에 적합한 특정 작업을 실행할 수 있습니다. 적절한 시점에 적절한 작업을 실행하고 전환을 올바르게 처리하면 앱의 견고성과 성능이 향상됩니다. 예를 들어 수명 주기 콜백을 올바르게 구현하면 앱에서 다음을 방지할 수 있습니다.

  • 사용자가 앱을 사용하는 동안 전화를 받거나 다른 앱으로 전환하면 비정상 종료됩니다.
  • 사용자가 적극적으로 사용하지 않을 때 귀중한 시스템 리소스를 소비합니다.
  • 사용자가 앱을 종료했다가 나중에 다시 돌아올 때 사용자의 진행 상황이 손실됩니다.
  • 화면이 가로 모드 방향과 세로 모드 방향 간에 회전할 때 비정상 종료되거나 사용자의 진행 상황이 손실됩니다.

이 문서에서는 활동 수명 주기에 관해 자세히 설명합니다. 이 문서는 수명 주기 패러다임을 설명하는 것으로 시작합니다. 다음으로 각 콜백을 설명합니다. 콜백이 실행되는 동안 내부적으로 발생하는 상황과 콜백 중에 구현해야 하는 사항을 설명합니다.

그런 다음 활동 상태와 시스템에 의해 종료될 수 있는 프로세스의 취약성 간의 관계를 간략하게 소개합니다. 마지막으로 활동 상태 간 전환과 관련된 몇 가지 주제를 설명합니다.

권장사항에 관한 안내를 비롯하여 수명 주기 처리에 관한 자세한 내용은 Jetpack Compose의 수명 주기 및 UI 상태 저장을 참고하세요. 활동을 아키텍처 구성요소와 함께 사용하여 강력한 프로덕션 품질의 앱을 설계하는 방법을 알아보려면 앱 아키텍처 가이드를 참고하세요.

활동 수명 주기 개념

활동 수명 주기의 단계 간 전환을 탐색하기 위해 Activity 클래스는 onCreate, onStart, onResume, onPause, onStop, onDestroy라는 핵심 콜백 6개를 제공합니다. 시스템은 활동이 새 상태로 전환될 때마다 이러한 콜백을 호출합니다.

그림 1은 이 패러다임을 시각적으로 보여줍니다.

그림 1. 활동 수명 주기를 단순화한 그림

사용자가 활동을 떠나기 시작하면 시스템은 활동을 해체하는 메서드를 호출합니다. 사용자가 다른 앱으로 전환하는 경우와 같이 활동이 부분적으로만 해체되고 메모리에 계속 남아 있는 경우도 있습니다. 이 경우 활동은 여전히 포그라운드로 돌아올 수 있습니다.

사용자가 활동으로 돌아오면 사용자가 중단한 지점부터 재개됩니다. 몇 가지 예외를 제외하고 앱은 백그라운드에서 실행 중일 때 활동을 시작할 수 없습니다.

시스템이 특정 프로세스와 그 안의 활동을 종료할 가능성은 당시 활동의 상태에 따라 달라집니다. 상태와 메모리에서 삭제될 가능성 간의 관계에 관한 자세한 내용은 활동 상태 및 메모리에서 삭제 섹션을 참고하세요.

활동의 복잡도에 따라, 모든 수명 주기 메서드를 구현할 필요가 없는 경우도 있습니다. 하지만 각 수명 주기를 이해하고 사용자가 기대하는 방식으로 앱이 작동하도록 수명 주기를 구현하는 것이 중요합니다.

Compose 및 수명 주기

Compose에서는 onStart 또는 onResume와 같은 활동 콜백 내에 비즈니스 로직이나 수동 관찰자 설정을 직접 배치하지 마세요. 대신 화면의 UI 상태에 자동으로 맞춰지는 수명 주기 인식 효과와 상태 인식 관찰자를 사용하세요.

  • 수명 주기 인식 수집: collectAsStateWithLifecycle를 사용하여 ViewModel에서 흐름을 사용합니다. 이 API는 UI가 Started 상태로 전환되면 자동으로 수집을 시작하고 백그라운드로 전환되면 중지하여 불필요한 리소스 소비를 방지합니다. 흐름을 상태로 수집한 후에는 LifecycleEffects를 사용하여 수명 주기 이벤트가 발생할 때 코드를 실행할 수 있습니다.
  • 로직 흐름: 이러한 API를 사용하면 UI가 컴포지션 트리를 통해 수명 주기 상태에 자연스럽게 반응하므로 사용자가 구성요소와 활발하게 상호작용할 때만 비즈니스 로직이 실행됩니다.

Compose 및 수명 주기에 관한 자세한 내용은 Jetpack Compose의 수명 주기를 참고하세요.

수명 주기 콜백

이 섹션에서는 활동 수명 주기 중에 사용되는 콜백 메서드에 관한 개념 및 구현 정보를 제공합니다.

일부 작업은 활동 수명 주기 메서드에 속합니다. 하지만 종속 구성요소의 작업을 구현하는 코드는 활동 수명 주기 메서드가 아닌 구성요소에 배치합니다. 이를 위해서는 종속 구성요소가 수명 주기를 인식하도록 해야 합니다. 종속 구성요소를 수명 주기 인식으로 만드는 방법을 알아보려면 Jetpack Compose의 수명 주기를 참고하세요.

onCreate

이 콜백은 시스템이 먼저 활동을 생성할 때 실행되는 것으로, 필수적으로 구현해야 합니다. 활동이 생성되면 생성됨 상태가 됩니다. onCreate 메서드에서 활동의 전체 수명 동안 한 번만 발생하는 기본 애플리케이션 시작 로직을 실행합니다.

예를 들어 onCreate 구현은 데이터를 목록에 결합하고 활동을 ViewModel와 연결하며 일부 클래스 범위 변수를 인스턴스화할 수 있습니다. 이 메서드는 이전에 저장된 활동 상태가 포함된 Bundle 객체인 savedInstanceState 매개변수를 수신합니다. 활동이 이전에 존재하지 않은 경우 Bundle 객체의 값은 null입니다.

활동의 수명 주기에 연결된 수명 주기 인식 구성요소가 있는 경우 ON_CREATE 이벤트를 수신합니다. @OnLifecycleEvent 주석이 달린 메서드가 호출되므로 수명 주기 인식 구성요소는 생성된 상태에 필요한 설정 코드를 실행할 수 있습니다.

다음 예는 최소한의 활동에 Text 컴포저블을 통합하는 방법을 보여줍니다.

class ExampleActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent { // In here, we can call composables!
            MaterialTheme {
                Greeting(name = "compose")
            }
        }
    }
}

@Composable
fun Greeting(name: String) {
    Text(text = "Hello $name!")
}

활동이 Created 상태로 유지되지 않습니다. onCreate 메서드가 실행을 완료하면 활동이 Started 상태로 전환되고 시스템이 onStart 및 onResume 메서드를 연속으로 빠르게 호출합니다.

onStart

활동이 Started 상태로 전환되면 시스템은 onStart를 호출합니다. 이 호출은 앱이 활동을 포그라운드로 전환하고 상호작용할 수 있도록 준비하는 동안 활동을 사용자에게 표시합니다. 예를 들어 이 메서드는 UI를 유지하는 코드가 초기화되는 위치입니다.

활동이 시작됨 상태로 전환되면 활동의 수명 주기에 연결된 모든 수명 주기 인식 구성요소가 ON_START 이벤트를 수신합니다.

onStart 메서드는 빠르게 완료되며, Created 상태와 마찬가지로 활동은 Started 상태로 유지되지 않습니다. 이 콜백이 완료되면 활동이 Resumed 상태로 전환되고 시스템이 onResume 메서드를 호출합니다.

onResume

활동이 재개됨 상태로 전환되면 포그라운드로 이동하고 시스템은 onResume 콜백을 호출합니다. 이 상태에 들어갔을 때 앱이 사용자와 상호작용합니다. 앱은 기기에서 전화를 받거나 사용자가 다른 활동으로 이동하거나 기기 화면이 꺼지는 등 앱에서 포커스를 가져가는 이벤트가 발생할 때까지 이 상태로 유지됩니다.

활동이 재개됨 상태로 전환되면 활동의 수명 주기에 연결된 모든 수명 주기 인식 구성요소가 ON_RESUME 이벤트를 수신합니다. 여기에서 수명 주기 구성요소는 구성요소가 표시되고 포그라운드에 있는 동안 실행해야 하는 기능(예: 카메라 미리보기 시작)을 사용 설정할 수 있습니다.

방해 이벤트가 발생하면 활동은 Paused 상태로 전환되고 시스템은 onPause 콜백을 호출합니다.

활동이 일시중지됨 상태에서 재개됨 상태로 돌아가면 시스템은 onResume 메서드를 다시 호출합니다. 따라서 onResume을 구현하여 onPause 중에 해제하는 구성요소를 초기화하고 활동이 재개됨 상태로 전환될 때마다 실행해야 하는 다른 초기화 작업을 실행합니다.

다음은 구성요소가 ON_RESUME 이벤트를 수신할 때 카메라에 액세스하는 수명 주기 인식 구성요소의 예입니다.

class CameraComponent : LifecycleObserver {
    ...
    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    fun initializeCamera() {
        if (camera == null) {
            getCamera()
        }
    }
    ...
}

위 코드는 LifecycleObserver가 ON_RESUME 이벤트를 수신하면 카메라를 초기화합니다. 그러나 멀티 윈도우 모드에서는 활동이 일시중지 상태에 있더라도 완전히 표시될 수 있습니다. 예를 들어 앱이 멀티 윈도우 모드에 있고 사용자가 활동을 포함하지 않는 창을 탭하면 활동이 일시중지됨 상태로 전환됩니다.

앱이 재개된 경우 (포그라운드에서 표시되고 활성 상태인 경우)에만 카메라를 활성화하려면 이전에 설명한 ON_RESUME 이벤트 후에 카메라를 초기화합니다. 활동이 일시중지되었지만 표시되는 동안(예: 멀티 윈도우 모드) 카메라를 활성 상태로 유지하려면 ON_START 이벤트 후에 카메라를 초기화합니다.

그러나 활동이 일시중지된 동안 카메라를 활성 상태로 유지하면 멀티 윈도우 모드에서 재개된 다른 앱이 카메라에 액세스하지 못할 수 있습니다. 활동이 일시중지된 동안 카메라를 활성 상태로 유지해야 하는 경우도 있지만, 이렇게 하면 실제로 전반적인 사용자 환경이 저하될 수 있습니다.

따라서 멀티 윈도우 모드 컨텍스트에서 공유 시스템 리소스를 제어하기에 가장 적절한 수명 주기 위치를 신중하게 고려해야 합니다. 멀티 윈도우 모드 지원에 관한 자세한 내용은 멀티 윈도우 모드 지원을 참고하세요.

초기화 작업을 실행하기 위해 선택한 빌드업 이벤트와 관계없이 상응하는 수명 주기 이벤트를 사용하여 리소스를 해제해야 합니다. ON_START 이벤트 후에 무언가를 초기화하는 경우 ON_STOP 이벤트 후에 이를 해제하거나 종료합니다. ON_RESUME 이벤트 후에 초기화하는 경우 ON_PAUSE 이벤트 후에 해제합니다.

위의 코드 스니펫은 카메라 초기화 코드를 수명 주기 인식 구성요소에 배치합니다. 대신 이 코드를 onStart 및 onStop과 같은 활동 수명 주기 콜백에 직접 넣을 수 있지만 권장하지는 않습니다. 이 로직을 수명 주기를 인식하는 독립적인 구성요소에 추가하면 코드를 복제하지 않고도 여러 활동에서 구성요소를 재사용할 수 있습니다. 수명 주기 인식 구성요소를 만드는 방법을 알아보려면 Jetpack Compose의 수명 주기를 참고하세요.

onPause

시스템은 사용자가 활동을 떠난다는 첫 번째 표시로 이 메서드를 호출합니다. 그렇다고 해서 항상 활동이 소멸되는 것은 아닙니다. 활동이 더 이상 포그라운드에 있지 않지만 사용자가 멀티 윈도우 모드에 있는 경우 여전히 표시됨을 나타냅니다. 활동이 이 상태로 전환되는 데는 여러 가지 이유가 있습니다.

  • onResume 콜백에 관한 섹션에 설명된 대로 앱 실행을 중단하는 이벤트는 현재 활동을 일시중지합니다. 가장 일반적인 경우입니다.
  • 멀티 윈도우 모드에서는 한 번에 하나의 앱만 포커스를 가지며 시스템은 다른 모든 앱을 일시중지합니다.
  • 대화상자와 같은 새로운 반투명 활동이 열리면 이 활동이 가리는 활동이 일시중지됩니다. 활동이 부분적으로 표시되지만 포커스가 없는 동안에는 일시중지된 상태로 유지됩니다.

활동이 일시중지됨 상태로 전환되면 활동의 수명 주기에 연결된 모든 수명 주기 인식 구성요소가 ON_PAUSE 이벤트를 수신합니다. 여기에서 수명 주기 구성요소는 구성요소가 포그라운드에 있지 않을 때 실행할 필요가 없는 기능(예: 카메라 미리보기 중지)을 중지할 수 있습니다.

onPause 메서드를 사용하여 Activity가 일시중지됨 상태에 있는 동안 계속할 수 없거나 적당히 계속할 수 있는 작업을 일시중지하거나 조정하고 곧 다시 시작할 것으로 예상합니다.

onPause 메서드를 사용하여 시스템 리소스, 센서 핸들 (예: GPS) 또는 활동이 일시중지되고 사용자가 필요로 하지 않는 동안 배터리 수명에 영향을 미치는 리소스를 해제할 수도 있습니다.

그러나 onResume에 관한 섹션에서 언급했듯이 앱이 멀티 윈도우 모드에 있는 경우 일시중지된 활동이 계속 완전히 표시될 수 있습니다. 멀티 윈도우 모드를 더 잘 지원하려면 onPause 대신 onStop를 사용하여 UI 관련 리소스와 작업을 완전히 해제하거나 조정하는 것이 좋습니다.

ON_PAUSE 이벤트에 반응하는 LifecycleObserver의 다음 예는 이전 ON_RESUME 이벤트 예에 대응하는 것으로, ON_RESUME 이벤트가 수신된 후 초기화되는 카메라를 해제합니다.

class CameraComponent : LifecycleObserver {
    ...
    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    fun releaseCamera() {
        camera?.release()
        camera = null
    }
    ...
}

이 예에서는 LifecycleObserver가 ON_PAUSE 이벤트를 수신한 후 카메라 해제 코드를 배치합니다.

onPause 실행은 매우 짧으며 저장 작업을 실행하기에 충분한 시간을 제공하지 않을 수 있습니다. 따라서 onPause를 사용하여 애플리케이션 또는 사용자 데이터를 저장하거나 네트워크 호출을 실행하거나 데이터베이스 트랜잭션을 실행하지 마세요. 이러한 작업은 메서드가 완료되기 전에 완료되지 않을 수 있습니다.

대신 onStop 중에 부하가 큰 종료 작업을 실행합니다. onStop 중에 수행하기에 적합한 작업에 관한 자세한 내용은 다음 섹션을 참고하세요. 데이터 저장에 관한 자세한 내용은 상태 저장 및 복원 섹션을 참고하세요.

onPause 메서드가 완료되었다고 해서 활동이 일시중지됨 상태를 벗어나는 것은 아닙니다. 대신 활동은 재개되거나 사용자에게 완전히 보이지 않게 될 때까지 이 상태로 유지됩니다. 활동이 재개되면 시스템은 onResume 콜백을 다시 호출합니다.

활동이 일시중지됨 상태에서 재개됨 상태로 돌아가면 시스템은 Activity 인스턴스를 메모리에 상주시키고 시스템이 onResume를 호출할 때 이 인스턴스를 호출합니다. 이 시나리오에서는 재개됨 상태로 이어지는 콜백 메서드 중에 생성된 구성요소를 다시 초기화할 필요가 없습니다. 활동이 완전히 보이지 않게 되면 시스템은 onStop를 호출합니다.

onStop

활동이 사용자에게 더 이상 표시되지 않으면 Stopped 상태가 되고 시스템은 onStop 콜백을 호출합니다. 새로 실행된 활동이 전체 화면을 가릴 때 발생할 수 있습니다. 또한 시스템은 활동 실행이 완료되고 종료되려고 할 때 onStop를 호출합니다.

활동이 중지됨 상태로 전환되면 활동의 수명 주기에 연결된 모든 수명 주기 인식 구성요소가 ON_STOP 이벤트를 수신합니다. 여기에서 수명 주기 구성요소는 구성요소가 화면에 보이지 않을 때 실행할 필요가 없는 기능을 모두 정지할 수 있습니다.

onStop 메서드에서 앱이 사용자에게 표시되지 않는 동안 필요하지 않은 리소스를 해제하거나 조정합니다. 예를 들어 앱에서 애니메이션을 일시중지하거나 세분화된 위치 업데이트에서 대략적인 위치 업데이트로 전환할 수 있습니다. onPause 대신 onStop를 사용하면 사용자가 멀티 윈도우 모드에서 활동을 보고 있는 경우에도 UI 관련 작업이 계속됩니다.

또한 onStop를 사용하여 상대적으로 CPU 집약적인 종료 작업을 실행합니다. 예를 들어 데이터베이스에 정보를 저장하기에 더 좋은 시간을 찾을 수 없는 경우 onStop 중에 저장할 수 있습니다. 다음 예시에서는 초안 메모의 콘텐츠를 영구 스토리지에 저장하는 onStop 구현을 보여줍니다.

override fun onStop() {
    super.onStop()

    // Delegate the save operation to the ViewModel, which handles the
    // background thread operations (e.g., using Kotlin Coroutines and Room).
    noteViewModel.saveDraft()
}

활동이 중지됨 상태로 전환되면 Activity 객체가 메모리에 상주합니다. 이 객체는 모든 상태 및 구성원 정보를 유지하지만 창 관리자에 연결되어 있지 않습니다. 활동이 재개되면 이 정보를 다시 호출합니다.

활동은 정지됨 상태에서 다시 시작되어 사용자와 상호작용하거나, 실행을 종료하고 사라집니다. 활동이 다시 시작되면 시스템은 onRestart를 호출합니다. Activity 실행이 완료되면 시스템은 onDestroy를 호출합니다.

onDestroy

onDestroy는 활동이 소멸되기 전에 호출됩니다. 시스템은 다음 두 가지 이유 중 하나로 이 콜백을 호출합니다.

  1. 사용자가 활동을 완전히 닫거나 활동에서 finish가 호출되어 활동이 종료됩니다.
  2. 기기 회전 또는 멀티 윈도우 모드 전환과 같은 구성 변경으로 인해 시스템에서 활동을 일시적으로 제거하는 경우

활동이 소멸됨 상태로 전환되면 활동의 수명 주기에 연결된 모든 수명 주기 인식 구성요소는 ON_DESTROY 이벤트를 수신합니다. 여기에서 수명 주기 구성요소는 Activity가 소멸되기 전에 필요한 모든 항목을 정리할 수 있습니다.

Activity에 로직을 넣어 소멸되는 이유를 확인하는 대신 ViewModel 객체를 사용하여 Activity의 관련 뷰 데이터를 포함합니다. 구성 변경으로 인해 Activity가 다시 생성되면 ViewModel는 아무 작업도 할 필요가 없습니다. ViewModel는 보존되어 다음 Activity 인스턴스에 전달되기 때문입니다.

Activity가 다시 생성되지 않으면 ViewModel에서 onCleared 메서드를 호출하여 소멸되기 전에 필요한 데이터를 정리할 수 있습니다. isFinishing 메서드를 사용하여 이 두 시나리오를 구분할 수 있습니다.

활동이 종료되는 경우 onDestroy는 활동이 수신하는 최종 수명 주기 콜백입니다. 구성 변경의 결과로 onDestroy가 호출되면 시스템은 즉시 새 활동 인스턴스를 만든 다음 새 구성의 새 인스턴스에서 onCreate를 호출합니다.

onDestroy 콜백은 onStop와 같은 이전 콜백에서 해제되지 않은 모든 리소스를 해제합니다.

Activity 상태 및 메모리에서 제거

시스템은 RAM을 확보해야 할 때 프로세스를 종료합니다. 시스템이 특정 프로세스를 종료할 가능성은 당시 프로세스의 상태에 따라 달라집니다. 프로세스 상태는 프로세스에서 실행 중인 활동의 상태에 따라 달라집니다. 표 1은 프로세스 상태, 활동 상태, 시스템이 프로세스를 종료할 가능성 간의 상관관계를 보여줍니다. 이 표는 프로세스가 다른 유형의 애플리케이션 구성요소를 실행하지 않는 경우에만 적용됩니다.

종료될 가능성

프로세스 상태

최종 활동 상태

가장 낮음

포그라운드(포커스가 있거나 포커스를 가져올 예정)

재개됨

낮음

표시됨 (포커스 없음)

시작됨/일시중지됨

높음

배경 (보이지 않음)

중지됨

가장 높음

비어 있음

소멸됨

표 1. 프로세스 수명 주기와 활동 상태 간의 관계

시스템은 메모리 공간을 확보하기 위해 절대 활동을 직접 종료하지 않습니다. 대신 활동이 실행되는 프로세스를 종료하여 활동뿐만 아니라 프로세스에서 실행되는 다른 모든 항목도 소멸시킵니다. 시스템에서 시작된 프로세스 종료가 발생할 때 활동의 UI 상태를 보존하고 복원하는 방법을 알아보려면 상태 저장 및 복원 섹션을 참고하세요.

사용자는 설정의 애플리케이션 관리자를 사용하여 상응하는 앱을 종료하는 방식으로 프로세스를 종료할 수도 있습니다.

프로세스에 관한 자세한 내용은 프로세스 및 스레드 개요를 참고하세요.

임시 UI 상태 저장 및 복원

사용자는 회전 또는 멀티 윈도우 모드로의 전환과 같은 구성 변경이 발생하더라도 활동의 UI 상태가 동일하게 유지될 것으로 기대합니다. 그러나 시스템은 이런 구성 변경이 발생하면 기본적으로 활동을 소멸시켜 활동 인스턴스에 저장된 모든 UI 상태를 제거합니다.

마찬가지로 사용자는 일시적으로 다른 앱으로 전환한 후 나중에 다시 사용하던 앱으로 돌아오면 UI 상태가 동일하게 유지될 것으로 기대합니다. 하지만 사용자가 다른 앱을 사용 중이고 활동이 중지된 동안 시스템은 애플리케이션 프로세스를 폐기할 수 있습니다.

시스템 제약 조건으로 인해 활동이 소멸되면 ViewModel (복잡한 비즈니스 로직 및 화면 상태용), Jetpack Compose rememberSaveable API (가벼운 UI 상태용) 또는 로컬 저장소를 조합하여 사용자의 임시 UI 상태를 보존합니다. 시스템 동작과 비교한 사용자 기대치 및 시스템에서 시작된 활동 및 프로세스 종료 전반에 걸쳐 복잡한 UI 상태 데이터를 가장 잘 보존하는 방법을 자세히 알아보려면 UI 상태 저장을 참고하세요.

rememberSaveable는 내부적으로 상태를 번들로 묶어 구성 변경과 시스템에서 시작된 프로세스 종료 모두에서 자동으로 유지되므로 활동 수준의 상용구 없이 원활한 환경을 제공합니다.

인스턴스 상태

사용자가 뒤로 버튼을 누르거나 활동이 finish 메서드를 호출하여 자체 소멸을 알리는 경우와 같이 정상적인 앱 동작으로 인해 활동이 소멸되는 몇 가지 시나리오가 있습니다.

사용자가 뒤로를 누르거나 활동이 자체적으로 종료되어 활동이 소멸되면 Activity 인스턴스에 관한 시스템과 사용자의 개념이 모두 영구적으로 사라집니다. 이러한 시나리오에서는 사용자의 기대치가 시스템의 동작과 일치하므로 추가 작업을 할 필요가 없습니다.

그러나 시스템 제약 (예: 구성 변경 또는 메모리 부족)으로 인해 시스템이 활동을 소멸시키는 경우 실제 Activity 인스턴스는 사라지지만 시스템은 이 인스턴스가 존재했다는 것을 기억합니다. 사용자가 활동으로 다시 이동하려고 하면 시스템은 활동이 소멸될 때의 상태를 설명하는 저장된 데이터 세트를 사용하여 활동의 새 인스턴스를 만듭니다.

시스템이 이전 상태를 복원하는 데 사용하는 저장된 데이터를 인스턴스 상태라고 합니다. 내부적으로는 키-값 쌍의 모음입니다. 기본적으로 시스템은 인스턴스 상태를 사용하여 사용자 텍스트 입력이나 스크롤 위치와 같은 UI 레이아웃에 관한 기본 정보를 저장합니다.

rememberSaveable를 사용하여 이 시스템 동작에 후크합니다. 활동 인스턴스가 소멸되었다가 재생성되면 rememberSaveable로 래핑된 모든 UI 상태가 자동으로 복원되며 추가 활동 수준 코드가 필요하지 않습니다.

그러나 활동에는 사용자 데이터, 네트워크 응답 또는 사용자의 진행 상황을 추적하는 멤버 변수와 같이 복원하려는 더 복잡한 상태 정보가 있을 수 있습니다. 인스턴스 상태 메커니즘 (그리고 확장된 rememberSaveable)은 메인 스레드에서 직렬화가 필요하고 시스템 프로세스 메모리를 사용하므로 사소한 양 이상의 데이터를 보존하는 데 적합하지 않습니다.

소량의 데이터 이상을 보존하려면 UI 상태 저장에 설명된 대로 영구 로컬 저장소, ViewModel 클래스, Compose 상태 호이스팅을 사용하는 결합된 접근 방식을 사용하세요.

rememberSaveable을 사용하여 간단하고 가벼운 UI 상태 저장

활동이 중지되기 시작하면 시스템은 상태 정보를 인스턴스 상태 번들에 저장할 준비를 합니다. 이 시스템 동작에 연결하려면 컴포저블 함수 내에서 직접 rememberSaveable를 사용합니다. rememberSaveable는 활동 재생성 전반에 걸쳐 사용자 텍스트 입력 또는 스크롤 위치와 같은 일시적인 UI 상태를 자동으로 저장하고 복원합니다.

게임에서 사용자의 진행 상황과 같은 가벼운 맞춤 상태 정보를 저장하려면 rememberSaveable를 사용하여 상태를 선언합니다. Compose 프레임워크는 내부적으로 인스턴스 상태 번들에 대한 직렬화를 처리합니다.

var userTypedQuery by rememberSaveable(typedQuery, stateSaver = TextFieldValue.Saver) {
    mutableStateOf(
        TextFieldValue(text = typedQuery, selection = TextRange(typedQuery.length))
    )
}

사용자 환경설정이나 데이터베이스용 데이터와 같은 영구 데이터를 저장하려면 활동이 포그라운드에 있을 때 적절한 기회를 활용하세요. 이러한 기회가 발생하지 않으면 onStop 메서드 중에 영구 데이터를 저장합니다.

저장된 인스턴스 상태를 사용하여 활동 UI 상태 복원

활동이 이전에 소멸된 후 다시 생성되면 상태 복원이 자동으로 이루어집니다. rememberSaveable를 사용하면 명시적 복원 로직을 작성하거나 null 번들을 확인하거나 활동 콜백을 재정의할 필요가 없습니다. 상태를 초기화하고 저장하는 코드는 활동이 다시 시작될 때 상태를 원활하게 복원합니다.

var userTypedQuery by rememberSaveable(typedQuery, stateSaver = TextFieldValue.Saver) {
    mutableStateOf(
        TextFieldValue(text = typedQuery, selection = TextRange(typedQuery.length))
    )
}

활동 및 탐색

앱은 사용자가 기기의 뒤로 버튼을 탭하거나 새 대상을 선택하는 경우와 같이 수명 주기 동안 화면 간에 여러 번 전환될 수 있습니다. 최신 Android 앱은 일반적으로 단일 활동 아키텍처를 사용합니다. 화면마다 새 Activity를 시작하는 대신 앱은 단일 Activity를 호스팅하고 Navigation 구성요소를 사용하여 이 활동 내에서 컴포저블 화면을 교체합니다.

최신 Compose 중심 탐색을 구현하는 방법을 알아보려면 Jetpack Compose Navigation 3 라이브러리 가이드를 참고하세요.

다른 활동에서 활동시작하기

활동은 특정 시점에 다른 활동을 시작해야 할 수 있습니다. 예를 들어 앱이 현재 화면에서 새 화면으로 이동해야 할 때 이러한 필요성이 발생합니다.

활동이 시작하려는 새 활동에서 결과를 다시 가져오려는지에 따라 startActivity 메서드 또는 startActivityForResult 메서드를 사용하여 새 활동을 시작합니다. 두 경우 모두 Intent 객체를 전달합니다.

Intent 객체는 시작하려는 정확한 활동을 지정하거나 실행하려는 작업 유형을 설명합니다. 시스템은 적절한 활동을 선택하며, 이 활동은 다른 애플리케이션에서 가져올 수도 있습니다. Intent 객체는 시작된 활동에서 사용할 소량의 데이터를 전달할 수도 있습니다. Intent 클래스에 관한 자세한 내용은 인텐트 및 인텐트 필터를 참고하세요.

startActivity

새로 시작된 활동이 결과를 반환할 필요가 없는 경우 현재 활동은 startActivity 메서드를 호출하여 새 활동을 시작할 수 있습니다.

자체 애플리케이션 내에서 작업할 때는 알려진 활동을 실행하기만 하면 되는 경우가 많습니다. 예를 들어 다음 코드 스니펫은 SignInActivity라는 활동을 실행하는 방법을 보여줍니다.

val context = LocalContext.current

Button(onClick = {
    val intent = Intent(context, SignInActivity::class.java)
    context.startActivity(intent)
}) {
    Text("Sign In")
}

외부 활동 시작

내부 앱 탐색은 Navigation에서 처리하지만 Activity에서 다른 활동을 시작해야 하는 경우도 있습니다. 이는 일반적으로 웹브라우저 열기, 이메일 전송, 사진 촬영과 같은 특정 작업을 실행하기 위해 외부 앱을 활용하려는 경우에 발생합니다.

이를 위해 Intent 객체를 사용하여 실행하려는 작업 유형을 설명하면 시스템이 다른 애플리케이션에서 적절한 활동을 실행합니다.

예를 들어 사용자가 이메일 메시지를 보낼 수 있도록 하려면 다음과 같은 인텐트를 만들면 됩니다.

val intent = Intent(Intent.ACTION_SEND).apply {
    putExtra(Intent.EXTRA_EMAIL, recipientArray)
}
startActivity(intent)

외부 활동을 실행하고 결과를 다시 가져와야 하는 경우 (예: 카메라 앱에 사진을 찍고 이미지를 반환하도록 요청) 지원 중단된 startActivityForResult 콜백 대신 최신 Activity 결과 API를 사용하세요.

활동 조정

한 활동이 다른 활동을 시작하면 두 개 활동 모두 수명 주기가 전환됩니다. 첫 번째 활동은 작동을 중지하고 일시중지됨 또는 중지됨 상태로 전환되는 반면 다른 활동은 생성됩니다. 이러한 활동이 디스크나 다른 위치에 저장된 데이터를 공유하는 경우, 두 번째 활동이 생성되기 전에 첫 번째 활동이 완전히 중지되지 않는다는 점을 이해해야 합니다. 대신 두 번째 활동을 시작하는 프로세스가 첫 번째 활동을 중지하는 프로세스와 겹칩니다.

수명 주기 콜백의 순서는 잘 정의되어 있습니다. 특히 두 활동이 동일한 프로세스(즉, 동일한 앱)에 있고 한 활동이 다른 활동을 시작하는 경우에 그렇습니다. 활동 A가 활동 B를 시작할 때 발생하는 작업 순서는 다음과 같습니다.

  1. 활동 A의 onPause 메서드가 실행됩니다.
  2. 활동 B의 onCreate, onStart, onResume 메서드가 순서대로 실행됩니다. 이제 활동 B에 사용자 포커스가 있습니다.
  3. 활동 A가 더 이상 화면에 표시되지 않으면 onStop 메서드가 실행됩니다.

이러한 수명 주기 콜백 시퀀스를 사용하면 한 활동에서 다른 활동으로의 정보 전환을 관리할 수 있습니다.

추가 리소스

활동 수명 주기에 관한 자세한 내용은 다음 추가 리소스를 참고하세요.

콘텐츠 보기