저번 3단계에서 'End Game' 버튼에 대한 리스너를 구현했는데,
이렇게 사용자가 게임을 종료하면 ScoreFragment에서는 점수를 보여주지 않는다.
우리는 ViewModel이 ScoreFragment에서 보여질 점수를 갖고 있기를 바란다.
그래서 우리는 ViewModel의 초기화동안 factory 패턴을 사용해 점수 값을 넘겨줄 것이다.
factory 패턴이 익숙하지 않을 수 있다.
지금 나에게 떠오르는 예시는 BitmapFactory 정도인데, factory 패턴은 이름 그대로 직관적인 패턴이다.
공장에서 제품을 틀로 찍어내듯 생산하는데
factory 패턴도 같은 클래스의 인스턴스를 찍어내듯 생산하게끔 만든 패턴이다.
이 때, 인스턴스를 리턴해주기 위해 메소드를 사용한다.
1. score 패키지 아래에 ScoreViewModel class를 만든다.
이 클래스는 ScoreFragment를 위한 ViewModel이다.
2. ScoreViewModel 클래스는 ViewModel를 상속한다.
최종 점수를 위한 생성자 파라미터를 추가한다.
3. ScoreViewModel 클래스에서 최종 점수를 저장하기 위한 score 변수를 추가한다.
class ScoreViewModel(finalScore: Int) : ViewModel() {
// The final score
var score = finalScore
init {
Log.i("ScoreViewModel", "Final score is $finalScore")
}
}
4. score 패키지 아래에 ScoreViewModelFactory class를 만든다.
이 클래스는 ScoreViewModel 객체를 인스턴스화 할 목적이다.
5. ScoreViewModelFactory 클래스는 ViewModelProvider.Factory를 상속한다.
여기서도 최종 점수를 위한 생성자 파라미터를 추가한다.
class ScoreViewModelFactory(private val finalScore: Int) : ViewModelProvider.Factory {
}
6. ScoreViewModelFactory에서 안드로이드 스튜디오가 구현되지 않은 추상 멤버가 있다고 에러를 보여준다.
이를 해결하기 위해 create() 메소드를 오버라이드한다.
create() 메소드에서 새롭게 만들어진 ScoreViewModel 객체를 리턴해준다.
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(ScoreViewModel::class.java)) {
return ScoreViewModel(finalScore) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
7. ScoreFragment에서 ScoreViewModel과 ScoreViewModelFactory를 위한 클래스 변수를 만들어준다.
private lateinit var viewModel: ScoreViewModel
private lateinit var viewModelFactory: ScoreViewModelFactory
8. ScoreFragment에서 onCreateView() 안에 binding 변수를 초기화한 후,
viewModelFactory(바로 위에서 만든 변수)를 초기화한다.
ScoreViewModelFactory를 사용해 인자의 bundle에서 최종 점수를
ScoreViewModelFactory의 생성자 파라미터로 넘겨준다.
viewModelFactory = ScoreViewModelFactory(ScoreFragmentArgs.fromBundle(requireArguments()).score)
9. onCreateView()에서 viewModelFactory 초기화 이후 viewModel 객체를 초기화한다.
ViewModelProvider.get() 메소드를 호출해 연결된 ScoreFragment의 context, viewModelFactory를 넘겨준다.
이는 viewModelFactory 클래스에 정의된 factory 메소드를 사용해 ScoreViewModel 객체를 만들어준다.
viewModel = ViewModelProvider(this, viewModelFactory).get(ScoreViewModel::class.java)
10. onCreateView() 메소드에서 viewModel 초기화 이후
ScoreViewModel안의 최종 점수를 scoreText의 text를 설정한다.
binding.scoreText.text = viewModel.score.toString()
주의 : 이 앱에서, ScoreViewModel을 위한 ViewModelFactory를 추가할 필요는 없다.
왜냐하면, 점수를 viewModel.score에 직접 할당할 수 있기 때문이다.
하지만 가끔은 viewModel이 초기화될 때, 데이터가 필요할 때가 있다.
이로써, ViewModel에 관한 codelab이 끝났다.
천천히 다음 codelab으로 넘어가보겠다.
'Android' 카테고리의 다른 글
Codelab으로 LiveData 알아보기 - 1. Add LiveData to the GameViewModel (0) | 2023.01.17 |
---|---|
Codelab으로 LiveData 알아보기 - 과정 소개 (2) | 2023.01.15 |
Codelab으로 ViewModel 알아보기 - 3. Implement click listener (0) | 2023.01.03 |
Codelab으로 ViewModel 알아보기 - 2. Populate the ViewModel (0) | 2022.12.23 |
Codelab으로 ViewModel 알아보기 - 1. Create the ViewModel (0) | 2022.12.15 |