Android - 데이터 손실시 onSaveInstanceState() 사용

2022. 4. 27. 17:38IT/안드로이드

반응형

기기 방향을 회전시, 새 방향에 맞게 Layout 을 변경해야 할 수 있다. 이러한 시나리오에서 앱의 동작을 살펴보자.

그러면 , 시스템은 모든 주기 콜백을 호출해 활동을 종료한다. 그담에 다시 모든 주기 콜백을 호출해 활동을 시작한다.

그래서 사용하는 값들이 모두 초기화 될수가 있다. 

이럴때 onSaveInstanceState() 를 사용해 번들 데이터를 저장해보자.

 

onSaveInstanceState() 메서드는, Activity가 소멸되면 필요할 수 있는 데이터를 저장하는데 사용하는 콜백이다. 

수명 주기 콜백 다이어그램에서 onSaveInstanceState()는 활동이 중지된 후 호출 된다. 또한 앱이 백그라운드로 전환 될 때마다 호출된다. 

onSaveInstanceState()를 안전 조치라고 생각하자.

미리 추가했던 onStop() 처럼 override 함수를 하나 추가하자.

override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState)
    Log.d(TAG, "!!!! onSaveInstanceState Called !!!!")
}

그리고 빌드후 어플을 실행한다. 가로 세로로 방향 전환을 해보면, 

Pause -> Stop -> SaveInstanceState 가 불려오는걸 확인할 수 있다. 

 

*********

이제 기존에 앱에서 쓰는 데이터를 화면 전환시 날아가지 않게 해보자.. 

 

1.

MainActivity.kt 파일 상단에서 클래스 정의 앞에 다음과 같이 상수를 추가한다.

const val KEY_REVENUE = "revenue_key"
const val KEY_DESSERT_SOLD = "dessert_sold_key"

class MainActivity : AppCompatActivity() {

 

아래 함수를 보면, outState 매개변수가 Bundle이다. 

 

override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState)
    Log.d(TAG, "!!!! onSaveInstanceState Called !!!!")
}

Bundle 은 Key-value 의 Pair 모음으로, Key가 항상 문자열이여야한다.

Int 및 Boolean 값과 같은 간단한 데이터를 번들에 넣을 수 있다. 

 

2.

onSaveInstanceState()에서, revenue 값을 putInt() 를 사용해서 번들에 넣어보장.

override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState)
    outState.putInt(KEY_REVENUE, revenue)
    outState.putInt(KEY_DESSERT_SOLD, dessertsSold)
    Log.d(TAG, "!!!! onSaveInstanceState Called !!!!")
}

putInt() 말고도, putFloat(), putString() 도 있다. 2가지 인수를 사용한다. 

( KEY 문자열, 저장할 실제값 ) 이다. 

그래서 위에 소스코드를 보면 outState.putInt(KEY값, 저장할 값) 으로 설정되어있다. 

 

3.

onCreate() 로 돌아가서, 매개 변수를 확인해보면, 아래와 같다. 

override fun onCreate(savedInstanceState: Bundle) {

onCreate() 는 호출될 때 마다 Bundle을 가져온다. 프로세스 종료로 인해 활동이 다시 시작되면,

저장한 번들이 onCreate()에 전달된다.  Activity가 다시 시작되었다면 onCreate()의 Bundle은 NULL이다.

따라서 번들이 null이 아니면, 이전에 알려진 지점에서 활동을 다시 생성하고 있음을 알 수 있다.

## 참고 ##
Activity 가 다시 생성되는 경우, 맨 위의 그림에서와 같이 onRestoreInstanceState() 콜백은, Bundle과 함께 onStart() 후에 호출된다. 대부분의 경우, onCreate() 에서 액티비티 상태를 복원한다. 그러나, onRestoreInstantState()는 onStart()후에 호출되므로, onCreate()가 호출 된 일부 상태를 복원해야 한다면, 이걸 사용하면 된다.

그래서, binding 변수가 설정된 직후에 아래의 코드를 onCreate()에 추가해본다. 

override fun onCreate(savedInstanceState: Bundle?) {

    super.onCreate(savedInstanceState)
    Log.d(TAG, "!!!! onCreate Called !!!!")
    // Use Data Binding to get reference to the views
    binding = DataBindingUtil.setContentView(this, R.layout.activity_main)

    Log.d(TAG, "savedInstanceState: "+savedInstanceState)
    if (savedInstanceState != null) {
        revenue = savedInstanceState.getInt(KEY_REVENUE, 0)
        dessertsSold = savedInstanceState.getInt(KEY_DESSERT_SOLD, 0)
    }

onCreate 함수 내에서, binding이 정의 된 이후에 아래의 소스를 추가한 것이다. 

if (savedInstanceState != null) {
    revenue = savedInstanceState.getInt(KEY_REVENUE, 0)
    dessertsSold = savedInstanceState.getInt(KEY_DESSERT_SOLD, 0)
}

공홈에서 발췌한 getInt() 함수의 설명이다. 

보면 key값은 String으로 된 키값이고, defValue를 왜 0으로 설정하나 했는데, 참조 값이 존재하지 않을경우에 return 하는 값이였군. (당연한걸 고민했군...^_ㅠ)

 

암튼 이렇게 추가하고, 컴파일하고 실행해보면, 기기를 회전해도 수정된 값이 바뀌지 않는것을 확인할 수 있다.

LOG : 

 

결론 !!!

기존에 유지하고싶은 데이터 값을 onSaveInstanceState() 여기다 넣으면 된다는 말씀 !~~~~~ㅎㅎ

 

## 요약 ## 

활동 수명 주기

  • 활동 수명 주기는 활동이 이동하는 일련의 상태입니다. 활동 수명 주기는 활동이 처음 만들어질 때 시작되고 활동이 소멸될 때 종료됩니다.
  • 사용자가 활동 간에 그리고 앱 안팎으로 이동할 때 각 활동은 활동 수명 주기의 상태 간에 이동합니다.
  • 활동 수명 주기의 각 상태에는 Activity 클래스에서 재정의할 수 있는 상응하는 콜백 메서드가 있습니다. 수명 주기 메서드의 핵심 집합은 다음과 같습니다. onCreate()onStart()onPause()onRestart()onResume()onStop()onDestroy()
  • 활동이 수명 주기 상태로 전환될 때 발생하는 동작을 추가하려면 상태의 콜백 메서드를 재정의합니다.
  • Android 스튜디오에서 스켈레톤 재정의 메서드를 클래스에 추가하려면 Code > Override Methods를 선택하거나 Control+o(Mac은 Command+o)를 누릅니다.

로그로 로깅

  • Android Logging API와 특히 Log 클래스를 사용하여 Android 스튜디오 내 Logcat에 표시되는 짧은 메시지를 작성할 수 있습니다.
  • Log.d()를 사용하여 디버그 메시지를 작성합니다. 이 메서드는 두 가지 인수를 사용합니다. 로그 태그(일반적으로 클래스 이름)와 로그 메시지(짧은 문자열)입니다.
  • Android 스튜디오에서 Logcat 창을 사용하여 작성한 메시지를 비롯한 시스템 로그를 확인합니다.

액티비티 상태 유지

  • 앱이 백그라운드로 전환되면 onStop()이 호출된 직후 앱 데이터를 번들에 저장할 수 있습니다. EditText의 콘텐츠와 같은 일부 앱 데이터는 자동으로 저장됩니다.
  • 번들은 키와 값의 모음인 Bundle의 인스턴스입니다. 키는 항상 문자열입니다.
  • onSaveInstanceState() 콜백을 사용하여 앱이 자동으로 종료된 경우에도 유지하려는 번들에 기타 데이터를 저장합니다. 번들에 데이터를 넣으려면 put으로 시작하는 번들 메서드(예: putInt())를 사용합니다.
  • onRestoreInstanceState() 메서드 또는 더 일반적인 onCreate()의 번들에서 데이터를 다시 가져올 수 있습니다. onCreate() 메서드에는 번들을 보유하는 savedInstanceState 매개변수가 있습니다.
  • savedInstanceState 변수가 null이면 활동이 상태 번들 없이 시작되어 검색할 상태 데이터가 없습니다.
  • 키를 사용하여 번들에서 데이터를 검색하려면 get으로 시작하는 Bundle 메서드(예: getInt())를 사용합니다.

구성 변경

  • 구성 변경은 기기 상태가 매우 급격하게 변경되어 시스템이 변경사항을 확인하는 가장 쉬운 방법이 활동을 소멸시키고 다시 빌드하는 것일 때 발생합니다.
  • 구성 변경은 사용자가 기기를 세로 모드에서 가로 모드로 또는 가로 모드에서 세로 모드로 회전할 때 가장 흔하게 발생합니다. 기기 언어가 변경되거나 하드웨어 키보드가 연결될 때도 구성 변경이 발생할 수 있습니다.
  • 구성 변경이 발생하면 Android는 모든 활동 수명 주기의 종료 콜백을 호출합니다. 그런 다음 Android는 처음부터 활동을 다시 시작하여 모든 수명 주기 시작 콜백을 실행합니다.
  • Android는 구성 변경으로 인해 앱을 종료할 때 onCreate()에서 사용할 수 있는 상태 번들로 활동을 다시 시작합니다.
  • 프로세스 종료와 마찬가지로 앱 상태를 onSaveInstanceState()의 번들에 저장합니다.

 

 

 

728x90
반응형

'IT > 안드로이드' 카테고리의 다른 글

Android - App architecture (1)  (2) 2022.05.02
onSaveInstanceState() 가 동작을 안한다?  (3) 2022.04.28
Android - 수명 주기 사용 사례  (5) 2022.04.27
Android - 수명 주기  (6) 2022.04.27
Android - RecyclerView  (6) 2022.04.20