유니 코드

[Android] 뽀모도로 타이머 만들기 with 코틀린(2) - 타이머 기능(CountDownTimer 사용) 본문

오늘의 공부는?!/Android

[Android] 뽀모도로 타이머 만들기 with 코틀린(2) - 타이머 기능(CountDownTimer 사용)

꼬물쥰 2022. 2. 17. 17:26

 

 

CountDownTimer

타이머 기능을 구현하기 위해서 CountDownTimer를 사용하였다.

사용자가 seekBar에서 타이머 시간을 설정하고 손을 떼는 순간 타이머가 실행된다. 

 

Kotlin

 object : CountDownTimer(30000, 1000) {

     override fun onTick(millisUntilFinished: Long) {
         mTextField.setText("seconds remaining: " + millisUntilFinished / 1000)
     }

     override fun onFinish() {
         mTextField.setText("done!")
     }
 }.start()

공식문서의 CountDownTimer이다. 

코드를 살펴보면 30초와 1초를 인자로 전달받았고(단위는 밀리세컨드: 1초 = 1000ms)

onTick()에서 1초마다 몇초가 남았는지 보여주고 

onFinish()에서 30초가 지나면 text를 done으로 설정한다.

 

 

MainActivity.kt

    private fun updateRemainTimes(remainMillis: Long){
        val remainSeconds = remainMillis / 1000

        remainMinutesTextView.text = "%02d".format(remainSeconds / 60)
        remainSecondsTextView.text = "%02d".format(remainSeconds % 60)
    }

남은 시간을 밀리세컨드 단위로 받아와서 두개의 textView의 text를 업데이트 해주는 함수

 

 

private fun updateSeekBar(remainMillis: Long){
    seekBar.progress = (remainMillis / 1000 / 60).toInt()
}

남은 시간을 받아와서 seekbar의 progress 설정해주는 함수

 

 

private fun createCountDownTimer(initialMillis: Long) =
    object : CountDownTimer(initialMillis, 1000L) {
        override fun onTick(millisUntilFinished: Long) {
            updateRemainTimes(millisUntilFinished)
            updateSeekBar(millisUntilFinished)
        }

        override fun onFinish() {
            updateRemainTimes(0)
            updateSeekBar(0)
        }
    }

 

 

countDownTimer는 추상클래스이기 때문에 onTick()과 onFinish()를 구현해주어야 한다.

위에서 만든 update함수들을 onTick()에서 사용해주어 1초마다 남은시간과 seekbar를 업데이트 해준다.

타이머가 완료되면 실행되는 함수가 onFinish()이므로 남은 시간을 모두 0으로 지정한다.

 

타이머와 SeekBar 연동

사용자가 seekbar에서 손을 떼면 타이머가 실행되도록 하기 위해 이전 게시글에서 구현한 bindView함수에 있는 onStopTrackingTouch를 수정한다.

override fun onStopTrackingTouch(seekBar: SeekBar?) {
    seekBar ?: return

    currentCountDownTimer = createCountDownTimer(seekBar.progress * 60 * 1000L)
    currentCountDownTimer?.start()
}

seekBar가 null일 경우 return을 해준다.

currentCountDownTimer 변수 null로 초기화하고 seekbar에서 시간 지정이 완료되면 타이머를 선언해주고 start()를 실행한다. 

 

seekbar를 다시 조정했을 때 타이머를 다시 실행하기 위해서 onStartTrackingTouch에서 cancel()하고 currentCountDownTimer 변수를 null로 초기화한다.

override fun onStartTrackingTouch(seekBar: SeekBar?) {
    currentCountDownTimer?.cancel()
    currentCountDownTimer = null
}

 

여기까지 하고 애뮬레이터를 실행했을 때 타이머를 실행시키고 다시 seekbar를 조절하여 타이머를 재실행시키면 남은 시간을 나타내는 숫자가 조금 이상하게 작동하는 것을 확인할 수 있다. 

이것은 onProgressChanged함수에서 fromUser인자가 true일 때만 updateRemainTimes함수를 실행시켜주면 해결된다.

override fun onStartTrackingTouch(seekBar: SeekBar?) {
    currentCountDownTimer?.cancel()
    currentCountDownTimer = null
}

 

 

결과 화면

 

 


Note

엘비스 연산자 ( ?: )

null 값을 허용하지 않는 변수에 null 값이 들어갔을 때 null 값을 변환할 수 있는 함수의 결과를 만들어 준다.

 

CountDownTimer

추상 클래스로 onTick()과 onFinish()를 구현해주어야 한다.

인자는 시작하는 시간과 진행되는 인터벌을 받는다.

 

onTick() - 인자로 받은 인터벌마다 실행

onFinish() - 타이머가 끝났을 때 실행

Comments