如何在 Kotlin / Android 中运行多个同时每秒更新一次 UI 的计时器?

问题描述 投票:0回答:1

为了稍微简化问题,我想在应用程序运行时运行多个计时器(并在应用程序重新打开时更新这些计时器)。如果你知道什么是放置游戏,那就是我试图实现的目标,或者甚至只是能够运行多个闹钟可能是非常相似的代码。

每次创建一个新的数据对象(存储在我的本地 Room DB 中)时,都应该创建一个从任意数字(比如 100)开始倒计时的新计时器。

对于每个新对象,该计时器应该保持唯一,因此如果您创建了 3 个计时器,它们都应该独立运行。

当他们达到 0 时,无论你在哪个屏幕或活动上,他们都应该触发数据库调用来做一些工作(不管是什么),然后(这是我最坚持的部分)无需用户交互即可动态更新 UI。

所以用户点击了几次按钮:

  • 创建 3 个定时器
  • 当每个计时器用完时,假设它向 UI 字段添加“1”
  • 所有计时器运行完毕后应该是 3(没有进一步的用户交互)

我也希望计时器能够在用户不在应用程序上时运行,或者至少在用户回来时更新。这不是绝对必要的,因为我可以通过检查当前时间、存储开始时间和结束时间来做到这一点,但我不确定这是最好的模式。

我尝试使用 WorkManager 来完成此操作,但无法使 UI 正确更新,而且我不完全确定我正在运行多个 UNIQUE 计时器,因为 WorkManager 似乎有点难以调试

android kotlin android-workmanager
1个回答
0
投票

实现此目的的一种方法是在您的 Android 应用程序中结合使用计时器和处理程序。

可以为每个新对象创建一个Timer,并将其引用存储在一个以对象的唯一标识为键的HashMap中。这样,您可以在需要时独立访问每个计时器。

在每个 Timer 的任务中,您可以将倒计时值减 1,并使用 Handler 更新 UI。您可以使用 Handler 的 postDelayed() 方法每秒更新一次 UI。这样,用户界面将在没有任何用户交互的情况下即时更新。

当计时器达到 0 时,您可以触发数据库调用来做一些工作并相应地更新 UI。

要处理应用程序未激活的情况,您可以使用 Android 的 AlarmManager 安排一个广播来唤醒您的应用程序并触发必要的操作。

这里有一些示例代码可以帮助您入门:

// Create a HashMap to store Timers
val timers = HashMap<Long, Timer>()

// Create a Timer for each new object
fun createTimer(id: Long, countdown: Int) {
    val timer = Timer()
    timer.scheduleAtFixedRate(object : TimerTask() {
        var remainingTime = countdown

        override fun run() {
            remainingTime--

            // Update the UI using a Handler
            val handler = Handler(Looper.getMainLooper())
            handler.postDelayed({
                // Update UI
                updateUI(id, remainingTime)

                // Trigger DB call and update UI when timer reaches 0
                if (remainingTime == 0) {
                    doDBWork(id)
                    updateUIAfterWork(id)
                    cancelTimer(id)
                }
            }, 1000)
        }
    }, 0, 1000)

    timers[id] = timer
}

// Cancel a Timer when required
fun cancelTimer(id: Long) {
    timers[id]?.cancel()
    timers.remove(id)
}

// Update the UI with the remaining time for a given object
fun updateUI(id: Long, remainingTime: Int) {
    // Update the UI for the given object
}

// Update the UI after the DB work is done for a given object
fun updateUIAfterWork(id: Long) {
    // Update the UI for the given object after DB work is done
}

// Trigger the DB work for a given object
fun doDBWork(id: Long) {
    // Trigger the DB work for the given object
}
© www.soinside.com 2019 - 2024. All rights reserved.