我想知道是否可以使用 kotlin 协程作为计时器,以便从代码中删除最大的 Java 引用。基本上我做了一个例子,我使用类 Timer 来处理计时器显示(毫秒精度)。看(注意 java 导入):
import javax.swing.*
import java.awt.FlowLayout
import java.util.*
import java.util.Timer
class Screen : JFrame() {
private var label = JLabel("--")
private var timer: Timer? = null
init {
setSize(600, 200)
defaultCloseOperation = 3
layout = FlowLayout()
val bt = JButton("toggle timer")
bt.addActionListener {
if (timer == null) {
val start = System.currentTimeMillis()
timer = Timer()
timer!!.scheduleAtFixedRate(object : TimerTask() {
override fun run() {
label.text = "elapsed milliseconds: ${System.currentTimeMillis() - start}"
}
}, 0, 1)
} else {
timer!!.cancel()
timer = null
}
}
add(label)
add(bt)
setLocationRelativeTo(null)
isVisible = true
}
}
fun main() {
Screen()
}
我还尝试用一些协程代码替换经典的 Timer 并得到了这个:
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import java.awt.FlowLayout
import javax.swing.JButton
import javax.swing.JFrame
import javax.swing.JLabel
fun create(someCallback: () -> Unit) = CoroutineScope(Job()).launch {
while (true) {
someCallback()
delay(1L)
}
}
class Screen : JFrame() {
var label = JLabel("--")
var localJob: Job? = null
init {
setSize(600, 200)
layout = FlowLayout()
val bt = JButton("toggle timer")
bt.addActionListener {
if (localJob == null) {
val start = System.currentTimeMillis()
localJob = create { label.text = "elapsed milliseconds: ${System.currentTimeMillis() - start}" }
} else {
localJob!!.cancel()
localJob = null
}
}
add(label)
add(bt)
setLocationRelativeTo(null)
isVisible = true
}
}
fun main() {
Screen()
}
我认为这两个代码基本上显示了实现之间的差异。不管怎样,我的问题是,与 Timer 类相比,我是否可以在性能方面简单地做到这一点。另外,如果有更好的方法来完成此行为而不是使用协程,请随时提出建议!
最佳答案
使用flow ,注意下面第一个启动 block
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
val clicks = MutableStateFlow(false)
suspend fun main(args: Array<String>) {
coroutineScope {
launch {
clicks.withIndex().collectLatest { (idx, value) ->
if (value) {
while (true) {
delay(1)
println("$idx label.text = ${System.currentTimeMillis()}")
}
}
}
}
launch {
clicks.value = true
delay(20)
clicks.value = false
delay(20)
clicks.value = true
delay(20)
clicks.value = false
delay(20)
clicks.value = true
delay(20)
clicks.value = false
delay(20)
clicks.value = true
delay(20)
clicks.value = false
delay(20)
}
}
}
我对swing不太了解,当按钮被点击时,切换值并将其设置为点击,现在一些解释
当事件发生时,collectLatest
将首先取消collectLatest中最后启动的协程,然后启动一个具有当前值的新协程,因此每次单击时,都会启动之前启动的协程while(true)
被取消,所以你不必处理取消事件,我认为这是最适合你的情况的解决方案
关于java - kotlin协程可以像java Timer一样使用吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68969379/