오늘도 삽질중

Android Rxjava interval 로 타이머 만들어보기 본문

안드로이드

Android Rxjava interval 로 타이머 만들어보기

Choi3950 2021. 10. 14. 00:08
반응형

내가 작업하는 앱에는 시간과 관련된 기능이 많다.

 

시간이 완료되면 다음 단계로 넘어가야하는 그런 작업이 상당히 많다.

 

이전까지는 제한시간이 2분 미만인 경우가 많아서

 

안드로이드에서 제공해주는 CountDownTimer 를 사용했었다.

 

그런데 최근에 제한시간이 1시간이 넘는 테스크가 생겼다.

 

동일하게 CountDownTimer로 적용을 해보니 뭔가 이상하다...시간이 한 80초 이상 넘어가면 가끔씩 시간이 맞지 않는것처럼 느껴질때가 있었다. 예를 들어 내가 280초로 설정을 해놓고 시간이 감소되는걸 보면 가끔씩 1초,2초가 빌때가 있다.

구글링을 해보니 CountDownTimer 의 고질적인 문제인듯 하다.

 

시간이 중요한 작업이라 고민을 하다 RxJava interval로 만들어 보는것을 생각했다.

구현하고 테스트해보니 크게 문제없이 잘 나오는거 같다.

 

구현방법은 모두 다르겠지만 나같은 경우에는 TextView를 상속받고 그 안에 Rx interval을 구현하는 식으로 작업했다.

import android.content.Context
import android.graphics.Color
import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatTextView
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.schedulers.Schedulers
import java.util.concurrent.TimeUnit

class RxTimerView @JvmOverloads constructor(
    context: Context,
    attr : AttributeSet,
    defStyleInt: Int = 0
) : AppCompatTextView(context,attr,defStyleInt) {

    private val compositeDisposable: CompositeDisposable = CompositeDisposable()
    var timerListener: TimerListener? = null

    init {
        setTextColor(Color.BLACK)
    }

    var time: Long = 0L
    set(value) {
        field = value

        //포맷형식에 따라 여러가지 시간표현가능
        val hh = "%02d".format((field / 1000) / 60 / 60 % 24)
        val mm = "%02d".format((field / 1000) / 60 % 60)
        val ss = "%02d".format((field / 1000) % 60)

        this.text = "남은시간 $hh:$mm:$ss"
    }

    fun startTimer(millisTime: Long) {
        compositeDisposable.add(
            Observable.interval(0 , 1000, TimeUnit.MILLISECONDS)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(Schedulers.io())
                .subscribe {
                    time = millisTime - (it*1000)
                    timerListener?.getTime(time)
                    if (time < 1000L) compositeDisposable.clear()
                }
        )
    }

    fun stopTimer(){
        compositeDisposable.clear()
        time = 0
    }

    interface TimerListener {
        fun getTime(time: Long)
    }



}

 

 

사용법은 TextView를 상속했기 때문에 xml에서 일반 TextView 쓰듯이 쓰면된다.

액티비티 단에서는 아래처럼 쓰면 된다.

 

        binding.timer.startTimer( 7202 * 1000 ) // 7202 초 * 1000 현재 작업한 형식대로면 02시간 00분 02초 동작체크
        binding.timer.stopTimer() //타이머 중지
        binding.timer.timerListener = object : RxTimerView.TimerListener{
            override fun getTime(time: Long) {
                //시간이 감소될때마다 해당 리스너로 감지된다.
            }
        }

 

혹시라도 더 좋은 타이머 구현 방법이나 팁이 있다면 공유부탁합니다.

반응형
Comments