Sam Story

savedInstanceState 본문

Android

savedInstanceState

Sam H 2024. 10. 30. 21:02

앱 개발을 하면서 프로젝트를 만들고

액티비티의 onCreate 메서드에 항상 있는 ' savedInstanceState '

오늘은 이 savedInstanceState 객체에 대해 포스팅 해보려 한다.

 

 

 

일단 이 savedInstanceState가 뭐고 어떤 역할을 하는지 설명하기에 앞서

생명주기에 대한 내용을 먼저 알고 있어야 한다.

 

 

Activity 생명주기

Activity Lifecycle

 

시스템 활동이 새 상태로 전환될 때

각 상태에 맞는 생명주기 메서드드를 호출한다.

 

그중에서 onCreate에 관한 공식문서 내용을 보면

 

lateinit var textView: TextView

// Some transient state for the activity instance.
var gameState: String? = null

override fun onCreate(savedInstanceState: Bundle?) {
    // Call the superclass onCreate to complete the creation of
    // the activity, like the view hierarchy.
    super.onCreate(savedInstanceState)

    // Recover the instance state.
    gameState = savedInstanceState?.getString(GAME_STATE_KEY)

    // Set the user interface layout for this activity.
    // The layout is defined in the project res/layout/main_activity.xml file.
    setContentView(R.layout.main_activity)

    // Initialize member TextView so it is available later.
    textView = findViewById(R.id.text_view)
}

// This callback is called only when there is a saved instance previously saved using
// onSaveInstanceState(). Some state is restored in onCreate(). Other state can optionally
// be restored here, possibly usable after onStart() has completed.
// The savedInstanceState Bundle is same as the one used in onCreate().
override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
    textView.text = savedInstanceState?.getString(TEXT_VIEW_KEY)
}

// Invoked when the activity might be temporarily destroyed; save the instance state here.
override fun onSaveInstanceState(outState: Bundle?) {
    outState?.run {
        putString(GAME_STATE_KEY, gameState)
        putString(TEXT_VIEW_KEY, textView.text.toString())
    }
    // Call superclass to save any view hierarchy.
    super.onSaveInstanceState(outState)
}

 

 

이런 내용을 간단하게 요약해 봤을 때

onCreate는 Activity가 처음 생성될때 호출되는 함수이고
Activity가 시작될 때 필요한 코드를 이곳에 작성한다.

onCreate는 savedInstanceState라는 Bundle 타입의 매개변수를 받는다.
이것은 Activity의 이전 상태를 저장하고 있다.
만약 이전에 Activity가 존재하지 않았다면, 즉 이번이 처음 생성하는 것이라면 savedInstanceState는 null이 들어있다.

 

최초 Activity가 만들어 졌을때 saveInstanceState는 null이고

saveInstanceState는 Activity가 일시적으로 삭제 될 때 호출되며

 

onSaveInstanceState() 콜백을 이용해서 savedInstanceState에 현재 상태를 저장할 수 있다.


onPause() - onStop() -  onSaveInstanceState()  순으로 호출된다.

 

 

 

onRestoreInstanceState()이전 상태를 복구하기 위한 복구 콜백이다.

 

onStart() - onRestoreInstanceState() - onResume() 순으로 호출되고

 

이전에 onSaveInstanceState()가 호출되지 않았으면 호출되지 않는다.

파라미터로 전달 되는 Bundle 객체에서 상태 복구에 필요한 데이터를 참조할 수 있다.

이 데이터는 사전 onSaveInstance()에서 백업해놓은 (key, value) 형식의 데이터인 것이다.

 

실제로 생명주기와 onSaveInstanceState() , onRestoreInstanceState() 에 로그를 찍고 확인해 보면

아래 그림과 같이 로그가 찍히는걸 볼 수 있다.

그러나 주의할 건 항상 onStop() 함수가 호출되고 그뒤에 onSaveInstanceState()가 호출되는 것은 아니다.

 

MainActivity가 올라와 있는 상태에서 뒤로가기 버튼을 눌렀을때를 보자.

 

이 상황에서는 onSaveInstanceState()가 호출되지 않는다.

이러한 이유는 상태를 보존할 필요가 없기 때문이다.

 onSaveInstanceState()는 액티비티의 재생성에 대비하여 현재 상태를 저장한다고 했다.

그러나 유저가 백버튼을 눌러 액티비티를 종료하는 건 원하는 종료이다.

유저가 직접 종료한 액티비티는 유저의 관심사 밖이며, 상태를 보존할 필요가 전혀 없다.

 

그렇기 때문에 onSaveInstanceState()가 호출되지 않는다.

 

직접 이 메서드들이 어떻게 작성되어 있는지 안드로이드 내부에서 확인해보자.

 

onSaveInstanceState()

onSaveInstanceState

 

현재 생명주기 객체가 LifecycleRegistry의 인스턴스인지 확인한다.

LifecycleRegistry는 생명주기 상태 변경을 관리하는 데 사용되는 클래스이다.

이 메서드는 액티비티가 일시적으로 파괴될 때 (예: 화면 회전 또는 다른 액티비티가 포그라운드로 나올 때)

필요한 상태 정보를 저장하는 데 사용된다.

이 메서드는 액티비티의 생명주기 상태를 관리하고,

기본적인 상태 저장 메커니즘을 호출하며, 추가적인 상태 정보를 저장하는 책임을 지고 있는 메서드인 것이다.

 

 

onRestoreInstanceState()

onRestoreInstanceState()
주석에 있는 설명을 번역하게 되면

 

이 메서드는 savedInstanceState에 제공된 이전 상태에서 액티비티가 다시 '초기화'될 때 onStart 이후에 호출됩니다.

대부분의 구현은 상태를 복원하기 위해 onCreate를 사용하지만,

모든 초기화가 완료된 후 여기에서 복원하는 것이 편리할 때도 있으며,

서브클래스가 기본 구현을 사용할지 결정할 수 있도록 하는 경우도 있습니다.

이 메서드의 기본 구현은 onSaveInstanceState에 의해 이전에 동결된 모든 뷰 상태를 복원합니다.

이 메서드는 onStart와 onPostCreate 사이에서 호출됩니다.

이 메서드는 액티비티를 재생성할 때만 호출되며, 다른 이유로 onStart가 호출될 경우에는 호출되지 않습니다.

 

매개변수:

  • savedInstanceState – onSaveInstanceState에서 가장 최근에 제공된 데이터입니다.

참고: onCreate, onPostCreate, onResume, onSaveInstanceState

 

요약하자면 위에서 설명한 이전 상태를 복구하기 위한 복구 콜백이라고 보면된다.

 

 

간단한 예제를 구현해서 확인해보자.

 

MainActivity

package com.example.savedinstancestateexample

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.TextView

class MainActivity : AppCompatActivity() {

    val TAG = "메인 액티비티"
    lateinit var textView: TextView
    var state: String? = null
    
    override fun onCreate(savedInstanceState: Bundle?) {
        Log.d(TAG, "onCreate: ")
        super.onCreate(savedInstanceState)

        state = savedInstanceState?.getString("상태")
        Log.d(TAG, "onCreate: 현재 상태는 ? : $state")

        setContentView(R.layout.activity_main)

        textView = findViewById(R.id.textView)
    }

    // 데이터를 복구
    override fun onRestoreInstanceState(savedInstanceState: Bundle) {
        Log.d(TAG, "onRestoreInstanceState: ")
        textView.text = savedInstanceState.getString("텍스트")
    }

    // 데이터를 저장
    override fun onSaveInstanceState(outState: Bundle) {
        Log.d(TAG, "onSaveInstanceState: ")
        outState.putString("텍스트","저장한 텍스트 입니다.")
        outState.putString("상태","저장한 상태 입니다.")
        super.onSaveInstanceState(outState)
    }
}

 

 

위처럼 코드를 작성하고 실행한 뒤 화면 Rotate를 바꾸게 되면

액티비티가 다시 초기화 된다.

 

실행화면

 

화면 변화에 따른 log

 

맨 처음 호출되는 onCreate()에서 state 변수는 null이고

화면을 돌렸을 때 호출되는 onCreate()에서

onSaveInstanceState()가 호출되었기 때문에 "저장한 상태 입니다." 값을 정상적으로 가져오는걸 볼 수 있다.

그 후에 onRestoreInstanceState()가 호출되서 기존 textView에 저장한 텍스트의 값이 나오는것도 볼 수 있다.

 

 

사실 그동안 코드를 작성하며 신경쓰지 않았던 코드였지만

개발자라면 내가 작성하는 코드가 뭘 의미하는지 전부 알아야 한다라는 말이 생각나

대수롭지 않게 여기던 것들이 눈에 들어오기 시작했다.

 

의도치 않은 process Kill이 일어났을때에 대한 대응으로 saveInstanceState를 사용할 수도 있고

항상 호출되는 lifecycle과 다르게 시스템 종료에 의한 내용으로도 다룰수도 있을것 같다.

 

사실 화면 rotate를 바꿨을 때 데이터를 보존하는 방법으로는 기존에 포스팅했던

AAC ViewModel을 사용해도 되지만 아래의 표를 보게되면

 

viewModel의 경우 시스템에 의한 Process Kill이 일어난 경우에는 데이터 유지가 안되는것이다.

 

 

그렇기 때문에 실제로 앱을 만들 때에는 두가지 전부를 이용해 앱을 만드는것이 필요하다.

 

 

참고 문헌 - 안드로이드 공식

 

https://developer.android.com/guide/components/activities/activity-lifecycle?hl=en

 

활동 수명 주기  |  Android Developers

활동은 사용자가 전화 걸기, 사진 찍기, 이메일 보내기 또는 지도 보기와 같은 작업을 하기 위해 상호작용할 수 있는 화면을 제공하는 애플리케이션 구성요소입니다. 각 활동에는 사용자 인터페

developer.android.com

 

'Android' 카테고리의 다른 글

안드로이드 MVI 패턴  (0) 2025.01.24
커스텀 다이얼로그 (custom Dialog)  (0) 2024.08.18
핸들러 (Handler)  (0) 2024.05.13
안드로이드 MVVM 패턴  (0) 2024.04.30
안드로이드 MVP 패턴  (0) 2024.04.29