| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | ||||||
| 2 | 3 | 4 | 5 | 6 | 7 | 8 |
| 9 | 10 | 11 | 12 | 13 | 14 | 15 |
| 16 | 17 | 18 | 19 | 20 | 21 | 22 |
| 23 | 24 | 25 | 26 | 27 | 28 | 29 |
| 30 |
Tags
- 안드로이드 카카오 로그인
- coroutine
- Android ViewPager2
- Android
- Kotlin
- 코틀린 코루틴
- 영어독립365
- DataBinding
- MVP Architecture
- Android Interceptor
- 카카오 알고리즘
- Android WebView
- Android Navigation
- Kotlin FCM
- 안드로이드
- android recyclerview
- 영어공부
- OkHttp Interceptor
- 프로그래머스 알고리즘
- 알고리즘 자바
- Java
- 안드로이드 갤러리 접근
- Android ProgressBar
- Android 12 대응
- Android Jetpack
- 66챌린지
- 습관만들기
- Android 12
- scope function
- WebView
Archives
- Today
- Total
나미래 Android 개발자
Android LiveData + ViewModel 사용 예제 본문
Jetpack.ViewModel과 LiveData를 이용한 옵저버 패턴
개요
LiveData와 ViewModel 그리고 Observer Pattern을 이용하여 화면에 보여지는 TextView(UI)의 값을 변경하는데 있어서 데이터 처리 로직과 UI 로직을 분리한다.
EditText에 값을 입력하여 더하기버튼 또는 빼기버튼 클릭 시, 산수 연산(데이터 처리 로직)을 ViewModel에서 처리하고 UI Controller(View)에서는 연산 값을 Observing하여 ViewModel에서 View에 UI 처리를 요청하지 않고 View단에서 자동으로 UI를 업데이트 하여 계산된 값을 보여준다.
실행 영상

build.gradle(Module) : ViewBinding 설정
build.gradle(Module) 파일에 안에 android { } 속성으로 아래 ViewBinding 설정을 위한 코드를 삽입한다.
viewBinding{
enabled = true
}
build.gradle(Module) 코드 전체
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
}
android {
compileSdk 31
defaultConfig {
applicationId "com.example.testlivedataviewmodel"
minSdk 26
targetSdk 31
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.6.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'
}
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">
<TextView
android:id="@+id/tv_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
android:textSize="30dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/et_input_number"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
app:layout_constraintEnd_toStartOf="@id/btn_plus"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_number" />
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btn_plus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="더하기"
app:layout_constraintBottom_toBottomOf="@id/et_input_number"
app:layout_constraintEnd_toStartOf="@id/btn_minus"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toEndOf="@id/et_input_number"
app:layout_constraintTop_toTopOf="@id/et_input_number" />
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btn_minus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="빼기"
app:layout_constraintBottom_toBottomOf="@id/et_input_number"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/btn_plus"
app:layout_constraintTop_toTopOf="@id/et_input_number" />
</androidx.constraintlayout.widget.ConstraintLayout>
NumberViewModel.kt: ViewModel 구현
enum class ActionType {
PLUS, MINUS
}
class NumberViewModel : ViewModel() {
companion object {
const val TAG = "태그"
}
// 내부에서 설정하는 자료형은 Mutable
// 변경가능하도록 설정
private val _currentValue = MutableLiveData<Int>()
// 변경되지 않는 데이터를 가져올 때 이름을 _ 언더스코어 없이 설정
// 공개적으로 가져오는 변수는 private 이 아닌 `public`으로 외부에서도 접근 가능하도록 설정
// 하지만 값을 직접 라이브데이터에 접근하지 않고 뷰모델을 통해 가져올 수 있도록 설정
val currentValue: LiveData<Int>
get() = _currentValue
// 초기값 설정
init {
Log.d(TAG, "NumberViewModel - 생성자 호풀: ")
_currentValue.value = 0
}
// 뷰모델이 가지고 잇는 값을 변경하는 메서드
fun updateValue(actionType: ActionType, input: Int) {
when (actionType) {
ActionType.PLUS -> _currentValue.value = _currentValue.value?.plus(input)
ActionType.MINUS -> _currentValue.value = _currentValue.value?.minus(input)
}
}
}
MainActivity.kt(UI-Controller): ViewModel + Observing Pattern
class MainActivity : AppCompatActivity() {
companion object {
const val TAG = "로그"
}
lateinit var myNumberViewModel: NumberViewModel
lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
myNumberViewModel = ViewModelProvider(this).get(NumberViewModel::class.java)
myNumberViewModel.currentValue.observe(this) {
Log.d(TAG, "MainActivity - myNumberViewModel - currentValue 라이브 데이터 값 변경: $it")
// UI Update
binding.tvNumber.text = it.toString()
}
binding.apply {
btnPlus.setOnClickListener {
val userInput = etInputNumber.text.toString().toInt()
myNumberViewModel.updateValue(ActionType.PLUS, userInput)
}
btnMinus.setOnClickListener {
val userInput = etInputNumber.text.toString().toInt()
myNumberViewModel.updateValue(ActionType.MINUS, userInput)
}
}
}
}'안드로이드 > LiveData + ViewModel' 카테고리의 다른 글
| Android Jetpack.LiveData in Kotlin (0) | 2022.05.26 |
|---|---|
| Android ViewModel in Kotlin (0) | 2022.05.24 |
Comments