Android Kotlin Fundamentals 05.1: ViewModel and ViewModelFactory 번역 #5
- study
- 2019. 11. 26. 22:19
Task: Create the GameViewModel
뷰모델 클래스는 UI와 관련된 데이터들을 저장하고 관리하도록 구현 됩니다. 이 앱에서는 각 뷰모델은 각 프레그먼트들과 연관되어 있습니다.
이번 태스크에서 뷰모델을 앱에 추가 해 볼 것입니다. GameFragment를 위한 GameViewModel을 추가 해 볼 것입니다. 이 코드랩을 진행 하면서 ViewModel이 라이프 사이클을 알고 잇다는 것 또한 배우게 될 것 입니다.
Step1 : Add The GameViewModel class
1. build.gradle(module:app) 파일을 열고 아래 dependencies를 추가해 줍니다. ViewModel과 관련된 dependency입니다.
//ViewModel
implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'
2. screens/game 폴더 안에 GameViewModel 클래스를 생성해 주세요.
3. GameViewModle클래스는 추상 클래스인 ViewModel을 상속해야 합니다.
4. ViewModel은 라이프 사이클을 인지하고 있다는 것을 잘 이해 할 수 있도록 GameViewModel 클래스의 init 블록에 아래와 같이 log를 추가해 주세요.
class GameViewModel : ViewModel() {
init {
Log.i("GameViewModel", "GameViewModel created!")
}
}
Step 2 : Override onCleared() and add logging
뷰모델은 연관되어 있던 프레그먼트가 detached 되었을 때 혹은 액티비티가 종료되었을 때, destroyed 됩니다. 뷰모델이 파괴되기 직전 onCleared() resources를 지우기 위해 콜백함수가 호출 됩니다.
- GameViewModel 클래스 안에 onCleared 함수를 override 해주세요.
- onCleared()안에 GameViewModel의 라이프사이클을 트래킹 할 수 있도록 로그를 추가 해 주세요.
override fun onCleared() {
super.onCleared()
Log.i("GameViewModel", "GameViewModel destroyed!")
}
Step 3: Associate GameViewModel with the game fagment
뷰모델은 UI 컨트롤러(프레그먼트 혹은 액티비티)와 연관이 되어있을 필요가 있습니다. 이 둘을 연관 짓기 위해서 UI 컨트롤러는 뷰모델을 참조하고 있어야 합니다.
이번 스텝에서는 GameViewModel 참조를 GameFragment에 추가해 보겠습니다. GameFragment 클래스에 상단에 아래와 같이 GameViewModel 필드를 추가해 줍니다.
private lateinit var viewModel: GameViewModel
Step 4: Initialize the ViewModel
화면 회전과 같이 설정 변경이 일어나는 동안 프레그먼트와 같은 UI 컨트롤러들은 재 생성 (re-created) 됩니다. 그러나 뷰모델 인스턴스는 살아 있습니다. 만약 뷰모델 인스턴스를 뷰모델 클래스를 사용해서 만들었다면, UI 컨트롤러 들이 재 생성 될 때 마다 뷰모델 또한 재생성 될 것입니다. 대신 ViewModelProvicer를 이용해서 뷰모델 인스턴스를 만들면 뷰모델은 UI 컨트롤러가 재생성 되더라도 살아 있습니다.
중요 : 뷰모델을 인스턴스화 시키기 위해서는 ViewModel 오브젝트를 통해 바로 인스턴스화 시키기 보다는 ViewModelProvider를 이용해야 합니다.
어떻게 ViewModelProvider가 동작하는지
- ViewModelProvider는 ViewModel이 존재한다면, 존재하는 ViewModel을 리턴합니다. 존재하지 않는다면 새로운 뷰모델은 하나 생성합니다.
- ViewModelProvider은 주어진 스코프(액티비티 혹은 프레그먼트)와 연관이 있는 뷰모델 인스턴스를 생성합니다.
- 생성된 뷰모델은 스코프들(액티비티 혹은 프레그먼트)이 살아 있을 동안 유지 됩니다. 예를 들어 만약 스코프가 프레그먼트라면 뷰모델은 프레그먼트가 detached 될 때 까지 살아 있습니다.
ViewModelProviders.of()를 사용하여 ViewModelProvier를 만들고 ViewModel을 초기화 합니다.
- GameFragment 클래스에서 뷰모델 변수를 초기화 합니다. 아래의 코드를 onCreateView()에 넣습니다. binding 변수가 정의된 다음 줄에 넣으면 됩니다. ViewModelProviders.of()를 사용하고, GameFragment의 Context를 해당 함수의 인자로 보내줍니다. (this)
- ViewModel이 초기화 된 곳 위에 로그를 하나 찍어줍니다.
Log.i("GameFragment", "Called ViewModelProviders.of")
viewModel = ViewModelProviders.of(this).get(GameViewModel::class.java)
3. 앱을 실행 시킵니다. 안드로이드 스튜디오에서 로그캣을 이용하여 "Game"으로 필터를 해서 로그를 살펴 봅니다. 로그캣에 보이는것 과 같이 GameFragment의 onCreateView()는 GameViewModel 인스턴스를 생성하는 ViewModelProviders.of()를 호출 합니다.
4. 이제 화면 회전을 해봅시다. 화면 회전을 할 때마다 GameFragment는 destroyed 되고 re-created 됩니다. 그리고 ViewModelProviders.of()가 항상 호출 됩니다. 재생성 될 때 GameFRagment의 onCreateView()가 불리기 때문이죠. 그러나 GameViewModel은 오직 한번 생성됩니다. 그리고 여러번의 화면 회전에도 더 이상 재생성 되거나 파괴되지 않습니다.
5. 게임을 나가 봅시다. GameFragment가 destroyed 될 것입니다. 그리고 연관된 ViewModel 역시 destroyed 됩니다. 이때 뷰모델이 가지고 있는 onCleared()가 호출 됩니다.