轮询一般由以下部分组成:
- 任务对象
- 存储任务对象的数据结构
- 死循环
- 循环终止条件
下面的例子中,通过 Kotlin 协程实现了一个自动关闭的轮询任务:
abstract class PollingTask {
private var finishCallback: (() -> Unit)? = null
abstract fun run()
fun realRun() {
run()
finishCallback?.invoke()
}
fun finishCallback(block: (() -> Unit)?) {
this.finishCallback = block
}
}
object Dispatcher {
private var task: Task? = null
private var queue: LinkedList<Task> = LinkedList()
private var pollingJob: Job? = null
private var isDoing: AtomicBoolean = AtomicBoolean(false)
private var isPolling = false
val handler = Handler(Looper.getMainLooper())
fun dispatch(task: Task) {
queue.add(task)
if (!isPolling) {
startPolling()
}
}
private fun startPolling() {
pollingJob = CoroutineScope(Dispatchers.IO).launch {
loop()
}
isPolling = true
}
private fun stopPolling() {
isPolling = false
pollingJob?.cancel()
}
private suspend fun loop() {
while (true) {
delay(1000)
// 当队列为空时,自动取消轮询
if (queue.isEmpty()) {
Log.i(this.javaClass.name, "正在取消轮询")
stopPolling()
return
}
// 当前存在任务正在执行,跳过
if (isDoing.get()) {
continue
}
Log.i(this.javaClass.name, "正在轮询,当前剩余: ${queue.size}")
task = queue.pop()
// 任务执行完成,更新状态
task?.finishCallback {
isDoing.set(false)
task = null
}
Log.i(this.javaClass.name, "当前剩余: ${queue.size}")
// 这里可以酌情考虑要不要使用 post
handler.post {
task?.realRun()
isDoing.set(true)
}
}
}
}