当前位置: 首页 > article >正文

Android 倒计时总结

文章目录

  • Android 倒计时总结
    • Handler方案
    • CountDownTimer方案
    • Timer方案
    • Flow方案
    • 总结
    • 源码下载

Android 倒计时总结

Handler方案

class MyHandler(private val intervalTime: Long, // 间隔private val totalTime: Long, // 总时长onTick: (Long) -> Unit, // 每秒回调onFinish: () -> Unit // 结束回调
) {private var runType = RunType.INITprivate var handler: Handler? = Handler(Looper.getMainLooper())private val weekOnTick = WeakReference(onTick)private val weekOnFinish = WeakReference(onFinish)private var currentTime = 0Lprivate val runnable = object : Runnable {override fun run() {if (currentTime > 0) {// 进行中currentTime -= intervalTimeweekOnTick.get()?.invoke(currentTime)handler?.postDelayed(this, intervalTime)} else {// 结束weekOnFinish.get()?.invoke()runType = RunType.STOP}}}fun start() {if (runType == RunType.RUNNING) returnrunType = RunType.RUNNINGif (currentTime == 0L) {currentTime = totalTime}handler?.post(runnable)}fun pause() {if (runType != RunType.RUNNING) returnrunType = RunType.PAUSEhandler?.removeCallbacksAndMessages(null)}fun stop() {runType = RunType.STOPhandler?.removeCallbacksAndMessages(null)currentTime = 0weekOnFinish.get()?.invoke()}fun release() {runType = RunType.INIThandler?.removeCallbacksAndMessages(null)handler = nullweekOnTick.clear()weekOnFinish.clear()}enum class RunType {INIT, RUNNING, PAUSE, STOP}
}

使用:

class HandlerFragment : BaseFragment() {private lateinit var tvCountDown: TextViewprivate lateinit var btnStart: Buttonprivate lateinit var btnPause: Buttonprivate lateinit var btnStop: Buttoncompanion object {@JvmStaticfun newInstance() = HandlerFragment()}private lateinit var myHandler: MyHandleroverride fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,savedInstanceState: Bundle?): View {return inflater.inflate(R.layout.fragment_handler, container, false)}override fun onViewCreated(view: View, savedInstanceState: Bundle?) {super.onViewCreated(view, savedInstanceState)tvCountDown = view.findViewById(R.id.tv_count_down)btnStart = view.findViewById(R.id.btn_start)btnPause = view.findViewById(R.id.btn_pause)btnStop = view.findViewById(R.id.btn_stop)myHandler = MyHandler(1000L, 10_000L, { time ->tvCountDown.text = "剩余时间:${time / 1000}s"}, {tvCountDown.text = "倒计时结束!"})btnStart.setOnClickListener {myHandler.start()}btnPause.setOnClickListener {myHandler.pause()}btnStop.setOnClickListener {myHandler.stop()}}override fun onDestroyView() {super.onDestroyView()myHandler.release()}}

CountDownTimer方案

class MyCountDownTimer(private val intervalTime: Long,private val totalTime: Long,onTick: (Long) -> Unit,onFinish: () -> Unit
) {private var runType = RunType.INITprivate val weekOnTick = WeakReference(onTick)private val weekOnFinish = WeakReference(onFinish)private var countDownTimer: CountDownTimer? = nullfun start() {if (runType == RunType.RUNNING) returnrunType = RunType.RUNNINGcountDownTimer = object : CountDownTimer(totalTime, intervalTime) {override fun onTick(p0: Long) {weekOnTick.get()?.invoke(p0)}override fun onFinish() {weekOnFinish.get()?.invoke()runType = RunType.STOP}}countDownTimer!!.start()}fun stop() {runType = RunType.STOPcountDownTimer?.cancel()weekOnFinish.get()?.invoke()}fun release() {countDownTimer?.cancel()countDownTimer = nullweekOnTick.clear()weekOnFinish.clear()}enum class RunType {INIT, RUNNING, STOP}
}

使用:

class CountDownTimerFragment : BaseFragment() {private lateinit var tvCountDown: TextViewprivate lateinit var btnStart: Buttonprivate lateinit var btnStop: Buttonprivate lateinit var countDownTimer: MyCountDownTimercompanion object {@JvmStaticfun newInstance() = CountDownTimerFragment()}override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,savedInstanceState: Bundle?): View {return inflater.inflate(R.layout.fragment_countdown_timer, container, false)}override fun onViewCreated(view: View, savedInstanceState: Bundle?) {super.onViewCreated(view, savedInstanceState)tvCountDown = view.findViewById(R.id.tv_count_down)btnStart = view.findViewById(R.id.btn_start)btnStop = view.findViewById(R.id.btn_stop)countDownTimer = MyCountDownTimer(1000L, 10_000L,{ time ->tvCountDown.text = "剩余时间:${time / 1000}s"},{tvCountDown.text = "倒计时结束!"})btnStart.setOnClickListener {countDownTimer.start()}btnStop.setOnClickListener {countDownTimer.stop()}}override fun onDestroyView() {super.onDestroyView()countDownTimer.release()}
}

Timer方案

class MyTimer(private val intervalTime: Long,private val totalTime: Long,onTick: (Long) -> Unit,onFinish: () -> Unit
) {private val mainHandler = Handler(Looper.getMainLooper())private var runType = RunType.INITprivate val weekOnTick = WeakReference(onTick)private val weekOnFinish = WeakReference(onFinish)private var timer: Timer? = nullprivate var currentTime = 0Lfun start() {if (runType == RunType.RUNNING) returnrunType = RunType.RUNNINGcurrentTime = totalTimetimer = Timer()timer!!.schedule(object : TimerTask() {override fun run() {if (currentTime <= 0) {mainHandler.post {weekOnFinish.get()?.invoke()}cancel()runType = RunType.STOP} else {currentTime -= intervalTimemainHandler.post {weekOnTick.get()?.invoke(currentTime)}}}}, 0, intervalTime)}fun stop() {if (runType != RunType.RUNNING) returnrunType = RunType.STOPtimer?.cancel()weekOnFinish.get()?.invoke()}fun release() {timer?.cancel()timer = nullweekOnTick.clear()weekOnFinish.clear()}enum class RunType {INIT, RUNNING, STOP}
}

使用:

class TimerFragment : BaseFragment() {private lateinit var tvCountDown: TextViewprivate lateinit var btnStart: Buttonprivate lateinit var btnStop: Buttonprivate lateinit var myTimer: MyTimercompanion object {@JvmStaticfun newInstance() = TimerFragment()}override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,savedInstanceState: Bundle?): View {return inflater.inflate(R.layout.fragment_timer, container, false)}override fun onViewCreated(view: View, savedInstanceState: Bundle?) {super.onViewCreated(view, savedInstanceState)tvCountDown = view.findViewById(R.id.tv_count_down)btnStart = view.findViewById(R.id.btn_start)btnStop = view.findViewById(R.id.btn_stop)myTimer = MyTimer(1000L, 10_000L,{ time ->tvCountDown.text = "剩余时间:${time / 1000}s"},{tvCountDown.text = "倒计时结束!"})btnStart.setOnClickListener {myTimer.start()}btnStop.setOnClickListener {myTimer.stop()}}override fun onDestroyView() {super.onDestroyView()myTimer.release()}
}

Flow方案

class MyFlow(private val intervalTime: Long,private val totalTime: Long,private val onTick: (Long) -> Unit,private val onFinish: () -> Unit,private val scope: CoroutineScope
) {private var runType = RunType.INITprivate val weekOnTick = WeakReference(onTick)private val weekOnFinish = WeakReference(onFinish)private var job: Job? = nullprivate var currentTime = 0Lfun start() {if (runType == RunType.RUNNING) returnrunType = RunType.RUNNINGjob = scope.launch {flow {currentTime = totalTimewhile (currentTime >= 0) {emit(currentTime)delay(intervalTime)currentTime -= 1000}}.collect {weekOnTick.get()?.invoke(it)if (it <= 0) {weekOnFinish.get()?.invoke()runType = RunType.STOP}}}}fun stop() {if (runType != RunType.RUNNING) returnrunType = RunType.STOPjob?.cancel()weekOnFinish.get()?.invoke()}fun release() {job?.cancel()job = nullweekOnTick.clear()weekOnFinish.clear()}enum class RunType {INIT, RUNNING, STOP}
}

使用:

class FlowFragment : BaseFragment() {private lateinit var tvCountDown: TextViewprivate lateinit var btnStart: Buttonprivate lateinit var btnStop: Buttonprivate lateinit var myFlow: MyFlowcompanion object {@JvmStaticfun newInstance() = FlowFragment()}override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,savedInstanceState: Bundle?): View {return inflater.inflate(R.layout.fragment_flow, container, false)}override fun onViewCreated(view: View, savedInstanceState: Bundle?) {super.onViewCreated(view, savedInstanceState)tvCountDown = view.findViewById(R.id.tv_count_down)btnStart = view.findViewById(R.id.btn_start)btnStop = view.findViewById(R.id.btn_stop)myFlow = MyFlow(1000L, 10_000L,{ time ->tvCountDown.text = "剩余时间:${time / 1000}s"},{tvCountDown.text = "倒计时结束!"},lifecycleScope)btnStart.setOnClickListener {myFlow.start()}btnStop.setOnClickListener {myFlow.stop()}}override fun onDestroyView() {super.onDestroyView()myFlow.release()}
}

总结

  • 简单需求:优先选用CountDownTimer,避免重复造轮子

  • 界面交互:使用Handler时注意与View的生命周期绑定

  • 后台任务:Timer方案需配合Service使用

  • 新项目推荐:采用Kotlin Flow实现,搭配协程更高效

  • 性能关键:避免在倒计时回调中执行耗时操作

  • 内存优化:所有方案都需注意释放资源

源码下载

http://www.lryc.cn/news/2392567.html

相关文章:

  • 基于 Redis 实现分布式锁:原理及注意事项
  • 手机设备多?怎样设置IP保证不关联
  • Linux 中常见的安全与权限机制
  • Golang|单例模式
  • 哈尔滨工业大学计算机系统大作业程序人生-Hello’s P2P
  • 小程序定制开发:从需求到落地,打造企业专属数字化入口
  • 【C/C++】基于 Docker 容器运行的 Kafka + C++ 练手项目
  • Linux系统管理与编程24:基础条件准备-混搭“本地+阿里云”yum源
  • 新一代Python管理UV完全使用指南|附实际体验与效果对比
  • 如何在 Windows 10 PC 上获取 iPhone短信
  • STM32程序运行不了,仿真功能也异常,连断点和复位都异常了
  • Linux 系统中的软链接与硬链接
  • Python爬虫第22节- 结合Selenium识别滑动验证码实战
  • 【C/C++】chrono简单使用场景
  • Escrcpy(安卓手机投屏软件) v1.29.6 中文绿色版
  • Oracle MOVE ONLINE 实现原理
  • Linux:深入理解网络层
  • 【设计模式】简单工厂模式,工厂模式,抽象工厂模式,单例,代理,go案例区分总结
  • Linux_编辑器Vim基本使用
  • vue展示修改前后对比,并显示修改标注diff
  • LiveWallpaperMacOS:让你的 Mac 桌面动起来
  • [预训练]Encoder-only架构的预训练任务核心机制
  • 07-后端Web实战(部门管理)
  • mysql ACID 原理
  • [Rust_1] 环境配置 | vs golang | 程序运行 | 包管理
  • 二十五、面向对象底层逻辑-SpringMVC九大组件之HandlerMapping接口设计
  • 构建安全高效的邮件网关ngx_mail_ssl_module
  • HUAWEI交换机配置镜像口验证(eNSP)
  • 前端vue3实现图片懒加载
  • 网站每天几点更新,更新频率是否影响网站收录