yourginieus
LifecycleObserver, onSaveInstanceState() 본문
1. 생명주기 오류 방지
- 라이프사이클 콜백에서 리소스를 설정할 때는 해제도 해 줘야 함
- onStart() 에서 무언가를 설정했을 경우, onStop()에서 정지 또는 해제해야 함
2. LifecycleObserver
- 내가 직접 onStart(), onStop() 등에서 리소스를 설정 및 해제할 필요 없이, Jetpack이 제공하는 licecycle library를 사용하면 component 자체가 라이프사이클의 변화를 감시하고 변화가 발생했을 때 필요한 작업을 수행함
- lifecycle library의 main parts
- Lifecycle owners : 라이프사이클을 가지는(소유하고 있는) 컴포넌트
- Activity와 fragment
- Lifecycle owerner는 LifecycleOwner 인터페이스를 생성함
- Lifecycle class : lifecycle owner의 실제 상태를 유지하고 lifecycle에 변화가 발생했을 때 이벤트를 일으킴
- Lifecycle observers : 라이프사이클 상태를 감시하고 라이프사이클이 변경되었을 때 작업을 수행함
- Lifecycle observers는 LifecycleObserver 인터페이스를 생성함
- 각 생명주기 때 실행됐으면 하는 함수에 주석으로 @OnLifecycleEvent(Lifecycle.Event.ON_START) 와 같이 달아주면 됨
- Lifecycle owners : 라이프사이클을 가지는(소유하고 있는) 컴포넌트
class DessertTimer(lifecycle: Lifecycle) : LifecycleObserver {
init {
lifecycle.addObserver(this)
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun startTimer() {
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun stopTimer()
- MainActivity 에서는
private lateinit var dessertTimer: DessertTimer
lateinit으로 변수를 선언한 후 onCreate 아래 쪽에서 초기화
dessertTimer = DessertTimer(this.lifecycle)
=> 이렇게 하면 onStart() 등에 직접적으로 선언하는 것보다 관리가 쉬움! 알아서 자동으로 라이프사이클 감지해주니까!
3. onSaveInstanceState()
- Android가 백그라운드에서 앱을 종료하면 앱과 데이터는 어떻게 되는가?
- 앱이 백그라운드로 이동해도, 앱은 destroyed 되지 않고 돌아갈 때까지 기다림
- 그러나 Android OS는 foreground에 있는 앱을 원활하게 실행하고 싶기 때문에 백그라운드의 앱은 덜 중요함
- 백그라운드에서 실행되는 앱의 처리량을 제한함
- 그래서 Android는 entire app process를 종료하기도 함! 이 시점에서는 추가 콜백이나 코드가 실행되지 않음
- 사용자가 해당 앱을 다시 열면 Android는 해당 앱을 재시작 함
**애뮬레이터에서 홈 버튼 눌러서 백그라운드로 이동하고 > Android studio 터미널에서
adb shell am kill com.example.android.dessertclicker(=앱 이름)
입력하기. 접속되어 있는 모든 애뮬레이터에 STOP 메세지를 전송하여 프로세스를 종료하는 것!
앱이 백그라운드에 있는 경우에만 해당됨
- 앱이 백그라운드에 있기 때문에 디바이스 화면에 프로세스가 중지되었음을 나타내는 표시는 보이지 않음
- onStop() 메소드가 호출되었음은 확인할 수 있고, onDestroy()는 실행되지 않았음을 알 수 있음 -> 그냥 액티비티가 종료되었을 뿐!
- 최근화면 버튼을 이용해 앱으로 돌아가면, 작업이 다시 시작됨
- 이 액티비티는 lifecycle callback의 전체 startup 순서를 따라 실행됨 -> onCreate() 부터 실행된다는 소리!
- 그럼 이전까지 내가 앱에 남겨 둔 데이터는 어떻게 되는가?
- OS가 앱을 재시작하면 Android는 앱을 이전 상태로 reset하려고 함
- Android는 사용자의 view 상태를 가져와서, activity에서 벗어날 때마다 bundle에 저장함
- EditText의 텍스트, activity의 백스텍이 자동으로 저장되는 데이터 중 하나임!
- 그러나 모든 데이터를 인식하지는 못할 수도 있음. 그럴 땐 데이터를 번들에 직접 추가해야 됨
STEP 1 : onSaveInstanceState() 를 사용하여 번들 데이터 저장하기
- onSaveInstanceState() 메소드는 Android OS가 앱을 파괴했을 때 필요한 데이터를 저장하기 위해 사용하는 콜백!
- Activity 생명주기 다이어그램에서, 액티비티가 stop된 후에 호출되는 것을 볼 수 있음 -> 앱이 백그라운드로 이동할 때마다 호출됨

- onSaveInstanceState를 사용하면 액티비티가 foreground를 벗어날 때 소량의 정보를 번들에 저장할 수 있음
- 매번 데이터를 저장하면 필요한 경우 복원할 수 있음
- MainActivity에서 onSaveInstanceState() 를 override하기
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
Timber.i("onSaveInstanceState Called")
}
- 이건 onPause와 onStop이 모두 일어난 직후 발생함
- 파일 맨 위에, 클래스 정의 직전에 key에 대한 상수 추가
const val KEY_REVENUE = "revenue_key"
const val KEY_DESSERT_SOLD = "dessert_sold_key"
const val KEY_TIMER_SECONDS = "timer_seconds_key"
- 이 키들은 instance state bundle에서 데이터를 저장하고 가져오는 데 모두 사용됨
- Bundle 타입인 outState 파라미터에 값 집어넣기
- Bundle은 key-value 쌍으로, key는 항상 문자열임
- value로는 primitive 값을 넣을 수 있음 - int, boolean
- 시스템은 이 번들을 RAM에 보관하기 때문에 번들 내의 데이터는 작은 것이 좋음
- 그리고 보통 10만 개보다 훨신 적은 수의 번들을 저장해야 함
- onStateInstanceState() 안에서, bundle에 넣고자 하는 값 넣기
outState.putInt(KEY_REVENUE, revenue)
- putFloat, putString 등도 가능
- 그리고 onCreate() 에서 번들 데이터 복원하기
- onCreate에는 기본적으로 Bundle? 타입의 savedInstanceState가 있음
- onCreate는 매번 Bundle을 호출하며, 프로세스가 종료된 후 activity가 restart되면 저장한 번들이 onCreate로 전달됨
- 따라서 액티비티가 새로 시작됐다면 Bundle은 null이고, null이 아니라면 기존 시점에서 activity를 재생성 하고 있음을 알 수 있음!
if (savedInstanceState != null) {
revenue = savedInstanceState.getInt(KEY_REVENUE, 0)
dessertsSold = savedInstanceState.getInt(KEY_DESSERT_SOLD, 0)
dessertTimer.secondsCount =
savedInstanceState.getInt(KEY_TIMER_SECONDS, 0)
}
- 번들에 값을 넣을 때 사용한 키값을 이용해 값 가져오기
- 뒤의 값은 번들 내에 해당 키에 대한 값이 존재하지 않는 경우의 기본값
- 보통 저 값들을 받은 후 해야하는 작업까지도 저 if 문 안에 넣어 줌
if (savedInstanceState != null) {
revenue = savedInstanceState.getInt(KEY_REVENUE, 0)
dessertsSold = savedInstanceState.getInt(KEY_DESSERT_SOLD, 0)
dessertTimer.secondsCount =
savedInstanceState.getInt(KEY_TIMER_SECONDS, 0)
showCurrentDessert()
}
'Android > Android Kotlin 기초 실습 정리' 카테고리의 다른 글
LiveData 및 LiveData Observer (0) | 2022.10.27 |
---|---|
ViewModel : ViewModelFactory (0) | 2022.10.26 |
Life Cycle 및 Logging - Timber (0) | 2022.10.26 |
Safe Args : 프래그먼트 간 데이터 전달, intent로 외부 앱 공유 (0) | 2022.10.26 |
Navigation : Navigation components, drawer 등 (0) | 2022.10.26 |
Comments