如何为带有各种片段的Kotlin Android应用创建带有协程的Singleton计时器?

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

在我用Kotlin制作的android应用中,我使用了Timer和Runnable来重复执行某些任务。但是,我很快遇到了问题,因为我的应用程序具有底部导航,因此,每次我单击不同的导航项(例如,主页,配置文件,设置等)并使用Runnable返回到片段时,都会执行计时器不稳定。在我看来,正在创建多个计时器,并且某种程度上它们并未被销毁。

一种快速的解决方案是使用Singleton,以便使用计时器初始化一个实例,并将其与我想要其重复的任何功能进行同步。

但是,来自Java,我不知道在Kotlin中使用Singleton。我进行了一些研究,发现要制作一个单例,您将其声明为object SingletonName,然后使用它即可。就这么简单(各种开发博客都提到过)

因此,我基本上希望一个计时器处于单一状态,然后在一个片段中以可运行的方式重复一定数量的任务,而不必维护另一个计时器。如何实现?

android kotlin timer singleton runnable
1个回答
0
投票

创建单例很容易。就像编写一样简单

object SyncTimer {

    //TODO:Your code here

}

因为我一直在进行UI操作,所以我想使用一个Co-routine,它将在Singleton本身中维护。

所以我在build.gradle(应用程序级别)中添加了依赖项

    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.2"

接下来,我们创建带有可运行程序的协同例程。对于我的用法,我将在Dashboard.kt文件中初始化可运行对象。 “信息中心”活动在底部导航中包含我的所有其他片段(家庭,个人资料,设置等)


object SyncTimer{
    //You can supply your own runnable from Fragments
    private lateinit var userRunnable: Runnable


    fun init (){
        val handler = Handler()

        GlobalScope.launch {

            if(userRunnable == null){
                userRunnable = Runnable {
                    Log.d("SyncTimer", "Working without any inputs")
                }
            }

            val swipeTimer = Timer()
            swipeTimer.schedule(object : TimerTask() {
                override fun run() {
                    handler.post(updateUi())
                }
            }, 1000, 2000)
        }
    }


    fun set(runnable : Runnable) {
        Log.d("SyncTimer", "A runner was provided")
        userRunnable = runnable
    }

    private fun updateUi(): Runnable{
        return userRunnable
    }

}

然后在我的Dashboard活动中,像onCreate()中那样初始化Runnable

        SyncTimer.init()

这样,计时器和可运行计时器已初始化。我的仪表板迅速默认为HomeFragment,在onCreateView()中我将自己的可运行变量传递给set()

val updateUi = Runnable {
                //Your code here
        }

        SyncTimer.set(updateUi) // <- Pass your runnable here

[如果您注意到了,我在单例中使用了if statement,如果userRunnable == null然后传递默认的runnalbe,则将其打印到日志中,“无需任何输入即可工作”但是,当我的应用程序启动时,我总是在logCat中看到“提供了跑步者”。这意味着Runnable从第一个实例开始就可以正常工作,而我通过SyncTimer.set()

将其传递给了Runnable

现在,即使我更改为其他片段,也将保持计时器。并且只有当我返回HomeFragment时,才会再次调用更新ui的代码。

因此,最干净的代码版本是:


object SyncTimer{
    private lateinit var userRunnable: Runnable

    fun init (){
        val handler = Handler()

        GlobalScope.launch {
            val swipeTimer = Timer()
            swipeTimer.schedule(object : TimerTask() {
                override fun run() {
                    handler.post(updateUi())
                }
            }, 1000, 2000)
        }
    }

    fun set(runnable : Runnable) {
        Log.d("SyncTimer", "A runner was provided")
        userRunnable = runnable
    }

    private fun updateUi(): Runnable{
        return userRunnable
    }

}

初始化为

SyncTimer.init()

传递可运行文件

val runnable = Runnable {
    //TODO: Do something
}

此代码的优点在于,您可以在不同的片段中传递不同的可运行对象,它们将在不创建任何新计时器的情况下全部正常工作。

改进此代码:

  • 如何用不同的timersdelays创建不同的periods
© www.soinside.com 2019 - 2024. All rights reserved.