在我用Kotlin制作的android应用中,我使用了Timer和Runnable来重复执行某些任务。但是,我很快遇到了问题,因为我的应用程序具有底部导航,因此,每次我单击不同的导航项(例如,主页,配置文件,设置等)并使用Runnable返回到片段时,都会执行计时器不稳定。在我看来,正在创建多个计时器,并且某种程度上它们并未被销毁。
一种快速的解决方案是使用Singleton,以便使用计时器初始化一个实例,并将其与我想要其重复的任何功能进行同步。
但是,来自Java,我不知道在Kotlin中使用Singleton。我进行了一些研究,发现要制作一个单例,您将其声明为object SingletonName
,然后使用它即可。就这么简单(各种开发博客都提到过)
因此,我基本上希望一个计时器处于单一状态,然后在一个片段中以可运行的方式重复一定数量的任务,而不必维护另一个计时器。如何实现?
创建单例很容易。就像编写一样简单
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()
现在,即使我更改为其他片段,也将保持计时器。并且只有当我返回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
}
此代码的优点在于,您可以在不同的片段中传递不同的可运行对象,它们将在不创建任何新计时器的情况下全部正常工作。
改进此代码:
timers
和delays
创建不同的periods
?