1) Activity Life Cycle
화면을 전환하니 cm 와 m 가 변경된다.
화면전환 시 데이터를 유지하기 위해서는
Activity Life Cycle 을 알아보아야 한다.
각 콜백이 언제 호출되는 지
여러가지 동작을 해보면서
앱을 껐다가 키거나
홈 버튼을 눌러서 다른 앱을 실행했다가 다시 오거나
뒤로가기 버튼을 누를 때
여러 화면을 전환할 때
방향을 전환 할 때
등등 다양한 활동을 할 때
어떻게 콜백이 호출되는 지 알아야
어떤 시점에 어떤 처리를 할 지 결정할 수 있다.
화면 방향 전환에 따른 Life Cycle 을 체킹하고
적절한 조치를 취함으로써 데이터를 유지하는 작업을 해보자.
2) Activity State 변경 처리
2-2) 구성 변경 발생 ( configuration change )
세로 모드와 가로 모드 간 방향 변경이 있을 때.
원래 Activity Instance 에서는 onPause(), onStop(), onDestroy() 콜백이 호출된다.
Activity의 새로운 인스턴스가 생성되면
이 인스턴스에는 onCreate(), onStart(), onResume() 콜백이 호출된다.
2-2) 임시 UI 상태 저장 및 복원
임시 UI 상태 저장하는 방법에는 3가지가 있다.
ViewModel, onSaveInstanceState(), 로컬 저장소 결합
2-2-1) UI 상태 저장 - onSaveInstanceState()
onSaveInstanceState() 를 이용해보자.
outState.putBoolean("cmToM", cmToM)
// UI 상태 저장
override fun onSaveInstanceState(outState: Bundle) {
// outState 에 값 저장
outState.putBoolean("cmToM", cmToM)
super.onSaveInstanceState(outState,)
}
2-2-2) UI 상태 복원
cmToM = savedInstanceState.getBoolean("cmToM")
// UI 샹태 복원
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
cmToM = savedInstanceState.getBoolean("cmToM")
// m/cm 글자 변경
binding.inputUnitTextView.text = if(cmToM) "cm" else "m"
binding.outputUnitTextView.text = if(cmToM) "m" else "cm"
super.onRestoreInstanceState(savedInstanceState)
}
숫자와 단위 모두 그대로 유지됨을 확인할 수 있다.
3) 전체 코드
MainActivity.kt
package com.part1.chapter3
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.PersistableBundle
import android.util.Log
import android.widget.TextView
import androidx.core.widget.addTextChangedListener
import com.part1.chapter3.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
// 바인딩 변수 선언
private lateinit var binding : ActivityMainBinding
var inputNumber : Int = 0 // 클래스 멤버 변수
var cmToM = true // 클래스 멤버 변수
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// binding 변수에 instance 할당
binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
// 뷰 참조 변수들 선언
val outputTextView = binding.outputTextView
val outputUnitTextView = binding.outputUnitTextView
val inputEditText = binding.inputEditText
val inputUnitTextView = binding.inputUnitTextView
val swapImageButton = binding.swapImageButton
// 문자열이 변경되면 알려주는 리스너
inputEditText.addTextChangedListener { text ->
inputNumber = if(text.isNullOrEmpty()) {
0
} else {
text.toString().toInt()
}
// cm -> m
if(cmToM) {
outputTextView.text = inputNumber.times(0.01).toString()
}else{
outputTextView.text = inputNumber.times(100).toString()
}
}
// 단위 변환 버튼 클릭 시 처리
swapImageButton.setOnClickListener {
cmToM = cmToM.not() // !cmToM
if (cmToM) {
inputUnitTextView.text = "cm"
outputUnitTextView.text = "m"
outputTextView.text = inputNumber.times(0.01).toString()
} else {
inputUnitTextView.text = "m"
outputUnitTextView.text = "cm"
outputTextView.text = inputNumber.times(100).toString()
}
}
}
// UI 상태 저장
override fun onSaveInstanceState(outState: Bundle) {
// outState 에 값 저장
outState.putBoolean("cmToM", cmToM)
super.onSaveInstanceState(outState)
}
// UI 상태 복원
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
cmToM = savedInstanceState.getBoolean("cmToM")
// m/cm 글자 변경
binding.inputUnitTextView.text = if(cmToM) "cm" else "m"
binding.outputUnitTextView.text = if(cmToM) "m" else "cm"
super.onRestoreInstanceState(savedInstanceState)
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<!-- 값 입력받는 EditText -->
<EditText
android:id="@+id/inputEditText"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:hint="자연수를 입력해주세요"
android:maxLength="7"
android:textColorHint="@color/purple_200"
android:textSize="30sp"
android:textColor="@color/purple_500"
android:textStyle="italic"
android:gravity="end"
android:inputType="number"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintVertical_bias="0.4"
app:layout_constraintHorizontal_bias="0.1"
/>
<!-- 입력받은 값을 처리하여 화면에 보여주는 TextView -->
<!-- inputEditText 오른쪽의 단위 표시할 TextView -->
<TextView
android:id="@+id/outputTextView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="28dp"
android:gravity="end"
android:text="100"
android:textColor="@color/black"
android:textSize="30sp"
app:layout_constraintEnd_toEndOf="@+id/inputEditText"
app:layout_constraintStart_toStartOf="@+id/inputEditText"
app:layout_constraintTop_toBottomOf="@id/inputEditText" />
<TextView
android:id="@+id/inputUnitTextView"
android:text="cm"
android:textSize="20sp"
android:layout_marginStart="16dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toEndOf="@id/inputEditText"
app:layout_constraintTop_toTopOf="@id/inputEditText"
app:layout_constraintBaseline_toBaselineOf="@id/inputEditText"
/>
<!-- outputTextView 오른쪽의 단위 표시할 TextView -->
<TextView
android:id="@+id/outputUnitTextView"
android:text="m"
app:layout_constraintStart_toEndOf="@id/outputTextView"
app:layout_constraintBaseline_toBaselineOf="@id/outputTextView"
android:textSize="20sp"
android:layout_marginStart="16dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<ImageButton
android:id="@+id/swapImageButton"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginStart="8dp"
android:src="@drawable/ic_baseline_swap_vert_24"
app:layout_constraintBottom_toBottomOf="@id/outputTextView"
app:layout_constraintStart_toEndOf="@id/inputUnitTextView"
app:layout_constraintTop_toTopOf="@id/inputEditText" />
</androidx.constraintlayout.widget.ConstraintLayout>
build.gradle (:app)
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
}
android {
namespace 'com.part1.chapter3'
compileSdk 33
defaultConfig {
applicationId "com.part1.chapter3"
minSdk 21
targetSdk 33
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
viewBinding {
enabled = true
}
}
dependencies {
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}
'안드로이드 앱(Kotlin|Java) > [2025~] 안드로이드 앱' 카테고리의 다른 글
Part1_Ch04_01 개요 및 학습목표 (0) | 2025.04.09 |
---|---|
Part1_Ch03_07 복습 및 한걸음 더 (0) | 2025.04.09 |
Part1_Ch03_05 단위변환 기능 구현 (0) | 2025.04.09 |
Part1_Ch03_04 UI 요소 가져오기 (0) | 2025.04.09 |
Part1_Ch03_03 길이변환 UI 그리기 (2) (0) | 2025.04.09 |