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", "倒计时被手动取消") } }