Developer Geek

Android LiveData + ViewModel 사용 예제 본문

안드로이드/LiveData + ViewModel

Android LiveData + ViewModel 사용 예제

devGeek 2022. 5. 20. 23:54
반응형

Jetpack.ViewModel과 LiveData를 이용한 옵저버 패턴

개요

LiveDataViewModel 그리고 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