(Kotlin)如何停止一个延迟的处理程序的执行?

wbgh16ku  于 2023-03-30  发布在  Kotlin
关注(0)|答案(1)|浏览(220)

我正在创建一个简单的节拍器应用程序。播放重复4节拍,第一个节拍带有重音。我为此使用了延迟处理程序。但当我单击停止按钮时,我希望该处理程序停止,但在终端中查看我的日志,我仍然在执行。有人可以帮助我吗?请。
我尝试使用函数mainHandler.removeCallbacksAndMessages(null),但当我查看日志时,处理程序仍在运行。
这些日志包含在代码中:

Log.d(“measureCount”,measureCount.toString())
Log.d(“accentPlayed”,(!accentPlayed &&!stopButtonPressed).toString())

在我的终端中,我仍然看到它们正在更新,这意味着来自处理程序的覆盖fun run()仍然在执行。但在这里,我希望该进程停止而不杀死应用程序。谢谢
验证码:

fun metronome() {

    var timer = 500

val timeSignatureTop = 4
    var accentPlayed = false
    var measureCount = 1

    val mainHandler = Handler(Looper.getMainLooper())

    mainHandler.post(object : Runnable {
        override fun run() {

            Log.d("measureCount", measureCount.toString())
            Log.d("accentPlayed", (!accentPlayed && !stopButtonPressed).toString())

            if (!accentPlayed && !stopButtonPressed) {
                mediaPlayerAccent!!.start()
                measureCount++
                accentPlayed = true
            }

            else if (measureCount < timeSignatureTop && !stopButtonPressed) {
                mediaPlayerBeat!!.start()
                measureCount++
            }

            else if (measureCount == timeSignatureTop && !stopButtonPressed) {
                mediaPlayerBeat!!.start()
                measureCount = 1
                accentPlayed = false
            }
            if (stopButtonPressed) mainHandler.removeCallbacksAndMessages(null)

            mainHandler.postDelayed(this, timer)
        }
    })
}

我试图使用函数mainHandler.removeCallbacksAndMessages(null),但是当我检查日志时,处理程序仍然在运行

bmvo0sr5

bmvo0sr51#

在你移除回调函数之后,你可以调用postDelayed,这样它又有了另一个回调函数,循环继续。你应该在移除回调函数之后在if语句中放入一个return(你需要加上括号)。
事实上,如果你这样做,并将if语句移动到函数的开头,你就不必一遍又一遍地检查isStopBuutonPressed
顺便说一句,我认为这个节拍器很可能会随着时间的推移而建立误差。我可能会尝试这样的东西来避免这种情况:

val nextTargetTime = System.currentTimeMillis() + timer

mainHandler.post(object : Runnable {
    override fun run() {

        //…

        nextTargetTime += timer
        val delay = nextTargetTime - System.currentTimeMillis()
        if (delay < 0) {
            // can’t keep up, skip one
            nextTargetTime -= timer
        }
        mainHandler.postDelayed(this, delay)

使用协程,我认为这种逻辑更容易写,因为你可以使用一个while循环,在循环结束时有一个延迟,并且在需要的时候跳出循环。

val interval = 500L
val timeSignatureTop = 4
var measureCount = 0L

lifecycleScope.launch {
    var beatCount = 0L // beat is counted from 0 up to timeSignatureTop-1
    val nextTargetTime = System.currentTimeMillis() + interval

    fun incrementBeat() {
        beatCount = (beatCount + 1) % timeSignatureTop
        if (beatCount == 0) measureCount++
    }

    while (!stopButtonPressed) {
        val player = if (beatCount == 0) mediaPlayerAccent!! else mediaPlayerBeat!!
        player.start()

        nextTargetTime += interval
        val delay = nextTargetTime - System.currentTimeMillis()
        if (delay < 0) {
            // can’t keep up, skip one
            nextTargetTime -= interval
            incrementBeat()
        }
        delay(delay)
        incrementBeat()
    }
}

相关问题