yourginieus
LiveData transformations 본문
1. Add a timer
- Android는 타이머를 구현할 때 사용할 수 있는 CountDownTimer라는 유틸리티 클래스를 제공함
- 우리는 단어 목록이 비었을 때 게임이 곧장 종료되는 대신 타이머가 종료될 때 게임이 종료되도록 할 것
- GameViewModel에 timer를 위한 로직을 추가하여 구성 변경 중에 타이머가 파괴되지 않도록 함
- fragment는 timer ticks를 통해 timer text view를 업데이트할 수 있는 코드를 포함하고 있음
- GameViewModel에 다음 지시들을 수행할 것!
- timer constants를 보관하는 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
}
- timer의 카운트다운 시간을 저장하려면, MutableLiveData 변수인 _currentTime과 그에 대한 backing property인 currentTime 생성하기
// Countdown time
private val _currentTime = MutableLiveData<Long>()
val currentTime: LiveData<Long>
get() = _currentTime
- private 유형의 CountDownTimer 타입의 member variable 추가하기 : timer
private val timer: CountDownTimer
- init 블록 안에서 start와 timer 초기화하기
- total time인 COUNTDOWN_TIME 과, 시간 간격을 위한 ONE_SECOND를 전달하기
- onTick()과 onFinish() 콜백을 override하고 타이머 시작하기
// 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()
- onTice() 구현 : 매 간격/매 tick 마다 호출됨
- 전달된 파라미터인 millisUntilFinished를 통해 _currentTime 업데이트
- millisUntilFinished : 타이머가 종료될 때까지의 시간(milliseconds단위)
- millisUntilFinished를 second로 변환하여 _currentTime에 할당
override fun onTick(millisUntilFinished: Long)
{
_currentTime.value = millisUntilFinished/ONE_SECOND
}
- onFinish() 콜백은 타이머가 종료될 때 호출됨
- _currentTime을 업데이트하고 game finish event를 호출함
override fun onFinish() {
_currentTime.value = DONE
onGameFinish()
}
- nextWord() 메소드 업데이트 : list가 비었을 때, 게임을 종료하지 않고 word list를 리셋하도록!
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)
}
}
- onCleared() 메소드 안에서, 메모리 누수를 방지하기 위해 timer cancle 하기
- 로그문은 삭제해도 됨
- onCleared는 ViewModel이 파괴되기 전에 호출됨
override fun onCleared() {
super.onCleared()
// Cancel the timer
timer.cancel()
}
- 이제 앱을 플레이하면, 60초가 지나면 게임이 자동종료됨 - 타이머 텍스트가 화면에 표시되지는 않음
2. Add transformation for the LiveData
- Transformations.map() 메소드는 source LiveData에서 데이터 조작을 수행하는 방법을 제공하고 result LiveData object를 반환함
- 이러한 Transformation은 옵저버가 반환된 LiveData object를 관찰하지 않는 한 계산되지 않음
- 이 메소드는 source LiveData를 사용하며 파라미터로 함수를 사용함
- 그 함수가 source LiveData를 조작함
- 전달되는 람다함수는 메인스레드에서 실행되므로 long-running tasks는 포함시키면 안됨
- 경과된 시간 LiveData object를 "MM:SS"의 new String LiveData object로 포맷함
- 또한 화면에 포맷된 경과 시간을 표시함
- game_fragment.xml 레이아웃 파일은 이미 timer text view를 가지고 있음
- 지금까지는 텍스트뷰가 표시할 텍스트가 없었기 때문에 보이지 않음!
- GameViewModel 클래스에서 currentTime을 인스턴스화한 후, currentTimeString 라는 LiveData object 새로 만들기
- 이 오브젝트는 currentTime을 문자열 버전으로 포맷하기 위함
- currentTimerString을 정의하기 위해 Transformations.map() 사용
- currentTime과 람다함수(to format the time) 을 인수로 전달
- DataUtils.formatElapsedTime() 유틸리티 메소드를 이용해 람다식을 구현할 수 있음
- 초 단위의 long 을 받아서 "MM:SS"로 포맷해 줌
// The String version of the current time
val currentTimeString = Transformations.map(currentTime) { time ->
DateUtils.formatElapsedTime(time)
}
- game_fragment.xml 에서 timer 텍스트뷰에, text 속성에 gameViewModel의 currentTimerString 할당
<TextView
android:id="@+id/timer_text"
...
android:text="@{gameViewModel.currentTimeString}"
... />
- 이제 앱을 실행하면 타이머 텍스트는 1초마다 업데이트되며 모든 단어를 다 써도 게임이 종료되지 않음 - 타이머가 다 되면 게임이 종료됨

'Android > Android Kotlin 기초 실습 정리' 카테고리의 다른 글
Recyclerview 기초 (0) | 2022.12.13 |
---|---|
Create a RoomDB (0) | 2022.10.27 |
ViewModel 및 LiveData를 통한 데이터 바인딩 (0) | 2022.10.27 |
LiveData 및 LiveData Observer (0) | 2022.10.27 |
ViewModel : ViewModelFactory (0) | 2022.10.26 |