95 lines
3.1 KiB
Kotlin
95 lines
3.1 KiB
Kotlin
package com.sw.platecabinet.utils
|
||
|
||
import kotlinx.coroutines.*
|
||
import kotlinx.coroutines.flow.*
|
||
import android.util.Log
|
||
import kotlinx.coroutines.flow.catch
|
||
import kotlinx.coroutines.flow.flowOn
|
||
import kotlinx.coroutines.flow.launchIn
|
||
import kotlinx.coroutines.flow.onCompletion
|
||
import kotlinx.coroutines.flow.onEach
|
||
import kotlinx.coroutines.flow.onStart
|
||
import java.util.concurrent.atomic.AtomicBoolean
|
||
import kotlin.ranges.downTo
|
||
|
||
/**
|
||
* 人脸识别防抖倒计时工具类(单例+防重复+无死循环)
|
||
*/
|
||
object CountDownUtil {
|
||
// 原子布尔值:标记是否正在倒计时(防重复启动)
|
||
private val isCounting = AtomicBoolean(false)
|
||
|
||
// 当前倒计时Job(用于取消)
|
||
private var currentJob: Job? = null
|
||
|
||
/**
|
||
* 启动/重启防抖倒计时(同一时间仅一个倒计时运行)
|
||
* @param totalSeconds 倒计时总秒数(如15)
|
||
* @param lifecycleScope Activity/Fragment的lifecycleScope(必须)
|
||
* @param onTick 每秒回调剩余秒数(主线程)
|
||
* @param onFinish 倒计时结束回调(主线程)
|
||
*/
|
||
fun startCountDown(
|
||
total: Int = 15,
|
||
lifecycleScope: CoroutineScope,
|
||
onStart: () -> Unit = {},
|
||
onTick: (Int) -> Unit = {},
|
||
onFinish: () -> Unit
|
||
) {
|
||
// 1. 防重复:如果正在倒计时,先取消旧任务
|
||
if (isCounting.get()) {
|
||
//cancelCountDown()
|
||
return
|
||
}
|
||
|
||
// 2. 标记为正在倒计时
|
||
isCounting.set(true)
|
||
|
||
// 3. 启动新倒计时
|
||
currentJob = flow {
|
||
Log.d("CountDownUtil", "倒计时启动,总时长:$total 秒")
|
||
for (i in total downTo 1) {
|
||
emit(i)
|
||
delay(1000) // IO线程等待1秒,无死循环
|
||
}
|
||
}
|
||
.flowOn(Dispatchers.IO) // 上游IO线程,避免阻塞主线程
|
||
.onStart {
|
||
withContext(Dispatchers.Main) {
|
||
onStart.invoke()
|
||
}
|
||
}
|
||
.onEach { remaining ->
|
||
// 主线程回调剩余时间
|
||
withContext(Dispatchers.Main) {
|
||
onTick.invoke(remaining)
|
||
}
|
||
}
|
||
.onCompletion {
|
||
// 倒计时结束:重置状态+回调
|
||
withContext(Dispatchers.Main) {
|
||
isCounting.set(false) // 重置标记
|
||
currentJob = null // 置空Job
|
||
Log.d("CountDownUtil", "倒计时正常结束")
|
||
onFinish.invoke()
|
||
}
|
||
}
|
||
.catch { e ->
|
||
// 捕获异常:避免崩溃,重置状态
|
||
Log.e("CountDownUtil", "倒计时异常:${e.message}", e)
|
||
isCounting.set(false)
|
||
currentJob = null
|
||
}
|
||
.launchIn(lifecycleScope)
|
||
}
|
||
|
||
/**
|
||
* 取消倒计时(手动停止)
|
||
*/
|
||
fun cancelCountDown() {
|
||
currentJob?.cancel() // 取消Job
|
||
currentJob = null // 置空,避免残留
|
||
isCounting.set(false) // 重置标记
|
||
Log.d("CountDownUtil", "倒计时被手动取消")
|
||
}
|
||
} |