본문 바로가기

Kotlin_study/CodeLab

[Codelab] ViewModel에 대해 이해하기

목차
1. 공부 이유

2. ViewModel이란?

3. View와 ViewModel의 역할

4. 후기, 이후 계획

5. 참고문헌

 

1. 공부 이유

리팩토링하는 과정에서 ViewModel을 적용하려다보니 어느 부분에서 적용하고, 어떻게 적용할지에 대한 고민이 들었다. 이 과정에서 내가 ViewModel을 제대로 이해하지 못하고 있다는 생각이 들었고, 적용 이전에 이에 대해 더 공부해보는 시간을 가질 필요를 느껴 Codelab에서 관련 내용에 대한 글을 읽고 공부하는 시간을 가졌다.

 

참고 Codelab 링크

Store data in ViewModel (android.com)


2. ViewModel 이란?

ViewModel은 데이터를 저장하는 안드로이드 아키텍처 구성요소 중 하나로 ViewModel에서 관리하는 데이터는 activity나 fragment가 소멸되어도 그 data를 잃지 않는다. 

//로그를 확인해보면 viewModel 객체가 재생성 되는 것을 확인할 수 있다
private val viewModel = GameViewModel()

//위의 코드와는 달리 fragment가 재생성될 때(ex. 화면 회전) viewModel은 데이터를 유지하고 있다
private val viewModel : GameViewModel by viewModels()

 

 

위의 코드처럼 ViewModel 객체 생성을 한다면 viewModel 객체를 생성한 View가 소멸되었다가 다시 시작할 때 새로운 인스턴스를 생성할 것이고, fragment가 생성될 때마다 ViewModel도 재생성될 것이다. 

 

그래서 ViewModel의 데이터를 유지하기 위해서는 속성 위임을 사용해야 한다. 아래의 코드가 속성 위임 방식으로 객체를 생성하는 코드인데, viewModel 객체의 일들을 viewModels가 대신해주게 책임을 넘겨주는 것이고, 이렇게 생성된 ViewModel 객체는 View가 재생성 될 때에도 이전에 생성한 인스턴스를 불러오기 때문에 데이터를 유지할 수 있는 것으로 이해했다. 

 

그리고 ViewModel 안에서의 데이터를 저장할 변수들은 private으로 선언하여 정보 은닉을 한다.

+ 지난 학기 OOP 시간에 배웠던 내용인데, 외부에서 변수를 읽거나 변경하기 위해서는 getter나 setter를 통해 하도록 제한하여야 데이터를 예상하지 않은 곳에서 조작할 수 없게끔 하기 위함인듯하다. 

private var _currentWordCount = 0
val currentWordCount : Int
        get() = _currentWordCount

위처럼 ViewModel에서 변수를 선언한다면 외부에서는 currentWordCount를 통해 변수를 읽는 것만 가능하고, ViewModel 내부에서는 _currentWordCount의 값을 조작하여 외부에 보여지는 데이터를 조작할 수 있을 것이다. 


3. View와 ViewModel의 역할

View(activity와 fragment)는 UI Controller로 사용자와 상호작용하는 부분의 작업을 담당하고, ViewModel에서는 UI에서 사용되는 데이터를 어떻게 처리할지(ex. 현재 점수 계산)을 담당한다.

//GameFragment.kt
private fun onSubmitWord() {
        val playerWord = binding.textInputEditText.text.toString()
        if(viewModel.isUserWordCorrect(playerWord)){
            setErrorTextField(false)
            if(viewModel.nextWord()){
                updateNextWordOnScreen()
            } else {
                showFinalScoreDialog()
            }
        } else {
            setErrorTextField(true)
        }
    }

//GameViewModel.kt
fun isUserWordCorrect(playerWord : String) : Boolean {
        if(playerWord.equals(currentWord, true)){
            increaseScore()
            return true
        }
        return false
    }
    
fun nextWord() : Boolean {
        return if(currentWordCount < MAX_NO_OF_WORDS){
            getNextWord()
            true
        } else false
    }

그래서 위의 코드처럼 사용자가 단어를 작성했을 때, 사용자가 입력한 단어와 정답이 일치하는지는 ViewModel에서 그리고 이 결과값을 바탕으로 어떻게 행동할지는 UI 컨트롤러에서 결정하게 책임을 분리하는 것이다. 

 

4. 후기, 이후 계획

덕분에 이번 시간에 ViewModel을 학습하면서 '뷰모델을 초기화할 때 왜 이런식으로 해야 하는 걸까?', '어떤 작업을 액티비티, 프래그먼트에서 해야 하는 것이고, 뷰모델에서 해야 하는 걸까?' 와 같은 의문점을 해결할 수 있었다. 이전까지는 다이얼로그 호출은 ViewModel에서 계산한 데이터 값을 통해 하는 작업이니까 ViewModel에서 해줘야 하는 건가? 라는 생각이 있었는데, 이를 정리할 수 있었던 시간이었다.

 

지난 포스팅에서 언급했듯이 livedata에 대한 이해도 더 해야 하기 때문에 이 또한 codelab을 통해 학습할 예정이다. 

확실히 학기 중에 틈틈이 공부해서 다 이해했다고 생각한게 잘못이었던것 같다. 

실습한 내용은 Github 링크를 통해 확인하실 수 있습니다.

 

참고 문헌

Store data in ViewModel (android.com)

ViewModel 개요  |  Android 개발자  |  Android Developers