많은 개발자들이 처음 안드로이드 개발에 입문할 때 알게 되는것이
안드로이드의 4대 컴포넌트일 것이다.
컴포넌트만 잘 이해하고 개발해도 좋은 품질의 앱을 만들 수 있다고 자부한다. (정말? ㅇㅇ)
오늘은 UI컨트롤러(Activity or Fragment)의 생명주기와 관련된 이야기를 하고자 한다.
많은 안드로이드 개발자들이 놓치는 것이 있다. 흔히들 UI컨트롤러를 다룰 때 onCreate()를 시작으로 onDestroy()가 되기까지의 한 사이클만을 생각하고, 개발을 하게 된다. 액티비티가 화면에 나온이상 Back 버튼이나 Recent Task 목록을 정리하지 않는 이상 액티비티는 살아 있다고 가정하고 개발을 하게 된다.
맞다. 보통은 그렇다. 하지만, 좋은 품질의 앱을 개발하기 위해서는 예외의 경우를 생각해야한다.

UI컨트롤러는 언제든지 부서질 수 있다.

요즘의 안드로이드기기는 넉넉한 RAM 과 CPU 퍼포먼스 덕에 빠르고 안정적으로 현재의 UI컨트롤러를 잘 유지하곤한다. 하지만 예전의 구형기기는 그렇지 못하여 액티비티가 포어그라운드에 있지 않은 경우는 종종 부서졌다가(onDestroy) 다시 되살아나곤 했다(onCreate)
이로 인해 onCreate시 xml을 다시 인플레이팅 하게 되고 이전 View의 상태값을 날아가게 된다.
쉽게 말해 이전 View의 상태를 기억하지 못한다. 또한 UIController에 멤버변수로 data를 담아두었다면, 이것마저도 잃게 된다.
한 번 테스트를 해보자.

간단히 TextView, EditText, Button을 이용하여 레이아웃을 구성했습니다.
TextView에는 Hint 속성에 “TextView 입력하신 값이 이곳에 출력됩니다” 라는 문구를 미리 넣어뒀습니다. EditText에 문자열을 입력하여 출력 버튼을 누르면 TextView에 출력하는 구조입니다.

Charles라는 문구를 입력하고 버튼을 눌렀더니 출력이 되는것을 확인할 수 있습니다.
이때 안드로이드 화면 회전을 하면 어떻게 될까요?

configuration change가 발생하기 때문에 UI컨트롤러가 다시 onCreate되면서 View를 다시 구성하게 됩니다. TextView도 초기화 되어 원래 있던 문구는 없어지고 Hint만 남게 되었습니다.
하지만, EditText의 경우 자동으로 text를 기억하게 되는데 이 기능을 비활성화 하려면android:saveEnabled = “false” 설정하면됩니다.

Note:View는 기본적으로 saveEnabled="true"가 기본값 입니다. view의 state를 저장한다는것이 text를 반드시 저장하는것은 아니며, View의 종류마다 state(상태)를 저장하는 방법도 다릅니다. 예를 들면 EditText,Button은 TextView를 상속한 컴포넌트들입니다. EditText는 text상태를 기억하지만 TextView 또는 Button은 text상태를 기억하지 않습니다.
View의 state저장값을 확인해보는 방법으로 saveInstanceState의 내부를 살펴볼 수 있습니다.

화면 회전을 통한 액티비티의 재생성말고 다른 방법도 있습니다. configurationChange를 만드는 더 좋은 방법도 있습니다.

개발자 옵션에서 “활동 보관 안 함” 이라는 옵션을 활성 해주시면, UI컨트롤러가 화면에서 사라질때마다 onDestroy가 되고 재진입할 때마다 onCreate되는것을 확인 해 보실수 있습니다.
개발할때 버그발생을 낮출수 있는 매우 유용한 기능이므로 개발시에는 켜두시고 사용하는것을 강력 권장합니다.

이제 configuration change가 발생했을때 TextView의 경우 text 속성을 유지 못한다는것을 알게 되었으니, TextView의 text를 원래대로 복구 할 수 있도록 해보겠습니다.
간단히 생명주기를 살펴보면

onCreate(savedInstanceState:Bundle?)
onSaveInstanceState(outState:Bundle?)
onResume()
onPause()
onRestoreInstanceState(savedInstanceState:Bundle?)
(or 프레그먼트의 경우 onViewStateRestore(savedInstanceState:Bundle?))
onDestroy()

순으로 콜백 메서드가 호출되게 됩니다.

onSaveInstance에서 bundle객체에 필요한 data를 저장하고
onRestoreInstanceState 또는 onViewStateRestore에서 받은 bundle로부터 data를 꺼내어
view의 상태를 복구 시키면 됩니다. 예제를 확인하도록 하겠습니다.

override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState)
    Log.e(TAG,"onSaveInstanceState"</span>)
    outState.putString("my_text", result.text.toString())//TextView의 text를 저장
}
override fun onViewStateRestored(savedInstanceState: Bundle?) {
    super.onViewStateRestored(savedInstanceState)
    Log.e(TAG,"onViewStateRestored")
    result.text = savedInstanceState?.getString("my_text")//미리 저장해둔 text를 복구
}

result라는 id를 갖는 TextView가 있고 현재 text를 bundle에 my_text라는 key로 저장하고 복구 하는 코드입니다.

전체 소스는 github에서 확인 가능합니다.

카테고리: 미분류

0개의 댓글

답글 남기기

Avatar placeholder

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.