이번에는 이전에 수정한 GuessTheWord 앱에 카운트다운을 위한 타이머를 추가한다.
단어 리스트가 비어있으면 게임이 끝나는 대신 타이머가 끝날 때 게임이 끝나도록 할 것이다.
이 때 사용될 유틸리티 클래스를 안드로이드에서는 제공하는데 CountDownTimer가 있다.
기기 설정 변경 도중 타이머가 destroy되지 않도록 ViewModel에 해당 로직을 추가한다.
프래그먼트는 타이머가 작동할 때마다 텍스트뷰를 업데이트하는 코드를 포함하고 있다.
GameViewModel 클래스에 아래 과정을 따라 구현한다.
1. 타이머 상수를 갖고 있기 위해 companion object를 만든다.
companion object {
// Time when the game is over
private const val DONE = 0L
// Countdown time interval
private const val ONE_SECOND = 1000L
// Total time for the game
private const val COUNTDOWN_TIME = 60000L
}
2. 카운트다운 시간을 저장하기 위해 _currentTime이라는 MutableLiveData 멤버 변수를 하나 추가하고
backing property로 currentTime을 추가한다.
// Countdown time
private val _currentTime = MutableLiveData<Long>()
val currentTime: LiveData<Long>
get() = _currentTime
3. private으로 CountDownTimer 타입의 timer 멤버 변수를 추가한다.
private val timer: CountDownTimer
4. 초기화 블럭 안에서 타이머를 초기화하고 시작한다.
총 시간으로는 COUNTDOWN_TIME, 시간 interval로는 ONE_SECOND를 사용한다.
// Creates a timer which triggers the end of the game when it finishes
timer = object : CountDownTimer(COUNTDOWN_TIME, ONE_SECOND) {
override fun onTick(millisUntilFinished: Long) {
}
override fun onFinish() {
}
}
timer.start()
5. 매 interval이나 tick에 호출되는 onTick 메소드를 구현한다.
_currentTime을 메소드의 파라미터를 사용해 업데이트한다.
p0는 타이머가 종료될 때까지의 시간(milliseconds)이다.
p0를 초 단위로 변환하고 _currentTime에 할당한다.
(현재 onTick 메소드를 IDE를 통해 자동완성하면 파라미터가 p0로 생성되는데
코드랩에서는 해당 파라미터를 millisUntilFinished로 소개하고 있다.)
override fun onTick(millisUntilFinished: Long)
{
_currentTime.value = millisUntilFinished/ONE_SECOND
}
6. onFinish 콜백 메소드는 타이머가 종료될 때 호출된다.
_currentTime을 업데이트하고 game finish 이벤트를 발생시키기 위해 onFinish 메소드를 implement한다.
override fun onFinish() {
_currentTime.value = DONE
onGameFinish()
}
7. 단어 리스트가 비어있으면 게임을 종료하는 대신 단어 리스트를 리셋하도록 nextWord 메소드를 수정한다.
private fun nextWord() {
// Shuffle the word list, if the list is empty
if (wordList.isEmpty()) {
resetList()
} else {
// Remove a word from the list
_word.value = wordList.removeAt(0)
}
}
8. onCleared 메소드에서 메모리 누수 방지를 위해 타이머를 취소한다.
onCleared 메소드는 ViewModel이 destroy되기 전에 호출된다.
override fun onCleared() {
super.onCleared()
// Cancel the timer
timer.cancel()
}
이제 앱을 실행하고 게임 시작 후 60초가 지나면 자동으로 게임은 종료된다.
하지만, 타이머 텍스트는 화면에 보이지 않을 것이다. 이 문제는 다음 글에서 해결해보도록 하자.
'Android' 카테고리의 다른 글
Codelab으로 LiveData transform해보기 - 3. 정리(完) (0) | 2023.05.23 |
---|---|
Codelab으로 LiveData transform해보기 - 2. Add transformation for the LiveData (0) | 2023.05.20 |
Codelab으로 DataBinding 알아보기 - 4. 정리(完) (1) | 2023.05.17 |
Codelab으로 DataBinding 알아보기 - 3. Add LiveData to data binding (0) | 2023.05.14 |
Codelab으로 DataBinding 알아보기 - 2. Add ViewModel data binding (0) | 2023.05.11 |