前言

关于倒计时可以说我们App开发中常见的一种场景了,比如Splash倒计时跳转首页,比如发送短信之后倒计时60秒显示等等。
关于倒计时的实现方式,大家可能有不同的做法,这里做一下总结看看你使用的是哪一种呢?

一、CountDownTimer的实现

  //倒计时的方式一fun countDownTimer() {var num = 60timer = object : CountDownTimer((num + 1) * 1000L, 1000L) {override fun onTick(millisUntilFinished: Long) {YYLogUtils.w("当时计数:" + num)if (num == 0) {YYLogUtils.w("重新开始")num = 60} else {num--}}override fun onFinish() {YYLogUtils.w("倒计时结束了..." + num)}}timer?.start()}private var timer: CountDownTimer? = nulloverride fun onDestroy() {super.onDestroy()timer?.cancel()
}

没什么花活,就是android.os包下面的 CountDownTimer 类的使用。内部实现使用了 Handler 进行封装。

二、直接用Handler的实现

private var handlerNum = 60private val mHandler = object : Handler(Looper.getMainLooper()) {override fun handleMessage(msg: Message) {when (msg.what) {1 -> {if (handlerNum > 0) {handlerNum--YYLogUtils.w("当时计数:" + handlerNum)countDownHander()} else {stopCountDownHander()}}}}}override fun onDestroy() {super.onDestroy()stopCountDownHander()}fun countDownHander() {mHandler.sendEmptyMessageDelayed(1, 1000)}fun stopCountDownHander() {mHandler.removeCallbacksAndMessages(null)}

我们可以直接使用Handler的延时发送消息实现倒计时。
当然另一种做法是使用 Runnable 来实现。

Handler handler = new Handler();Runnable runnable = new Runnable() {@Overridepublic void run() {recLen++;txtView.setText("" + recLen);handler.postDelayed(this, 1000);}public void test(){handler.postDelayed(runnable, 1000);
}

三、直接用Time、TimeTask的实现

以上是Android的倒计时方案,其实Java的Api也是支持倒计时实现的,比如 Timer 配合 TimerTask 就可以实现简单的倒计时。

   fun countDownTimer2() {var num = 60val timer = Timer()val timeTask = object : TimerTask() {override fun run() {num--YYLogUtils.w("当时计数:" + num)if (num < 0) {timer.cancel()}}}timer.schedule(timeTask, 1000, 1000)}

四、使用Theard倒计时

我们可以通过Thread的sleep方法来实现倒计时,不过由于是子线程我们不能更新UI,所以还是需要配合Handler实现。

    private var mThread: Thread = Thread(this)private var mflag = falseprivate var mThreadNum = 60override fun run() {while (mflag && mThreadNum >= 0) {try {Thread.sleep(1000)} catch (e: InterruptedException) {e.printStackTrace()}val message = Message.obtain()message.what = 1message.arg1 = mThreadNumhandler.sendMessage(message)mThreadNum--}}private val handler = Handler(Looper.getMainLooper()) { msg ->if (msg.what == 1) {val num = msg.arg1//由于需要主线程显示UI,这里使用Handler通信YYLogUtils.w("当时计数:" + num)}true}//开启倒计时fun countDownThread() {if (!mThread.isAlive) {mflag = trueif (mThread.state == Thread.State.TERMINATED) {mThread = Thread(this@DemoCountDwonActivity)if (mThreadNum == -1) mThreadNum = 60mThread.start()} else {mThread.start()}} else {mflag = false}}override fun onDestroy() {super.onDestroy()mflag = false}

这里的销毁线程我没有使用stop方法,已经不推荐我们使用,我们使用flag来判断即可。

五、使用框架RxJava

这样的线程并不是我们想要的,我们通常并不会直接new Thread 来进行一些逻辑操作,比如我们可能使用RxJava框架,通过操作符的方式来进行倒计时。
比我们倒计时4秒之后跳转页面的实现:

      val SHOTDOWN_TIME = 4val mDisposables : Disposable? = nullObservable.interval(0, 1, TimeUnit.SECONDS).take(SHOTDOWN_TIME.toLong()).map {return@map SHOTDOWN_TIME - it}.observeOn(AndroidSchedulers.mainThread()).subscribe({LogUtil.e(it.toString())}, {it.printStackTrace()}, {checkJump()}, {mDisposable = it})override fun onDestroy() {super.onDestroy()mDisposable?.dispose()}

注意我们还是需要通过mDisposable对象在页面销毁的时候释放,以免内存泄露,有没有简单一点方式?

六、Kotlin Flow 的实现

上面的方法都需要销毁资源,好麻烦,能不能自动取消?协程不就行了。
是的 lifecycleScope 根据生命周期自动取消的协程作用域,配合Flow的操作符完成倒计时岂不是完美。
好吧,你是自动倒计时了。结束之后取消协程,销毁也能取消协程,那如果我想手动的取消倒计时怎么办?比如倒计时60秒我就要在第50秒的时候强制取消协程怎么办?
launch方法返回的不就是Job 对象吗?根据此上下文对象不就可以取消协程了吗?
看看灵活的Flow倒计时如何实现。
定义一个扩展方法:

/*** 倒计时的实现*/
@ExperimentalCoroutinesApi
fun FragmentActivity.countDown(time: Int = 5,start: (scop: CoroutineScope) -> Unit,end: () -> Unit,next: (time: Int) -> Unit
) {lifecycleScope.launch {// 在这个范围内启动的协程会在Lifecycle被销毁的时候自动取消flow {(time downTo 0).forEach {delay(1000)emit(it)}}.onStart {// 倒计时开始 ,在这里可以让Button 禁止点击状态start(this@launch)}.onCompletion {// 倒计时结束 ,在这里可以让Button 恢复点击状态end()}.catch {//错误YYLogUtils.e(it.message ?: "Unkown Error")}.collect {// 在这里 更新值来显示到UInext(it)}}
}

使用:

     fun startCountDown() {var timeDownScope: CoroutineScope? = nullcountDown(time = 60,start = {timeDownScope = itYYLogUtils.e("开始")},end = {YYLogUtils.e("结速倒计时")toast("结速倒计时")},next = {YYLogUtils.w("当时计数:" + it)if (it == 50) {timeDownScope?.cancel()}})}

无需onDestory中销毁资源,如果想自由手动的控制倒计时,我们在start的高阶函数中接收父协程的上下文对象即可自动控制。

总结

倒计时的实现是我们常用的功能,如果你的项目是Kotlin构建的,那么我建议使用Flow来实现这种功能,使用扩展函数进行封装,使用起来更加的简单。

如果你们项目是Java语言实现的,那么同样的可以选择一种方式进行一个工具类的封装,也能达到同样的效果,只是记得需要在onDestory中销毁资源哦。

如有错漏还望指出,如有更多或更好的方法,也可以在评论区交流讨论。

如果感觉本文对你有一点点点的启发,还望你能点赞支持一下,你的支持是我最大的动力。

Ok,这一期就此完结。

————————————————
原文链接:https://juejin.cn/post/7128947531471388709

Android实现倒计时的几种方案相关推荐

  1. 实现倒计时的几种方案汇总

    前言 关于倒计时可以说我们App开发中常见的一种场景了,比如Splash倒计时跳转首页,比如发送短信之后倒计时60秒显示等等. 关于倒计时的实现方式,大家可能有不同的做法,这里做一下总结看看你使用的是 ...

  2. Android阴影实现的几种方案

    作者:newki 链接: https://juejin.cn/post/7149706291261210654 圆角容器?自定义圆角容器?自定义圆角加阴影容器? 太难了,不知道大家有没有同款UI设计师 ...

  3. Android性能优化的5种方案

    指标 量化性能的指标有很多,但最重要的就是以下5种: 包大小 响应时间 内存 CPU 耗电量 优化性能就是可以从以上5点入手. 包大小优化 顾名思义就是减少apk包体积大小,apk大小主要取决于res ...

  4. Android TextView滚动的两种方案

    方案有两个 1使用Android原生TextView,优点是简单,缺点是一旦失去焦点,就无法滚动了. 2自定义TextView,缺点是稍微麻烦点,优点是可以一直滚动. 方案1 使用Android原生T ...

  5. Android设置壁纸的几种方案

    Android设置壁纸有许多方法,主要思路有两种: 1:通过WallpaperManager设置 2:通过系统程序设置 下文将分开说明: <1>通过WallpaperManager设置 该 ...

  6. android 屏幕录制方案,Android录屏的三种方案

    本文总结三种用于安卓录屏的解决方案: adb shell命令screenrecord MediaRecorder, MediaProjection MediaProjection , MediaCod ...

  7. Android 屏幕适配的一种方案

    转载请标明出处: http://blog.csdn.net/xuehuayous/article/details/51671937 本文出自:[Kevin.zhou的博客] 前言:在<Andro ...

  8. Android音频录制方案,Android录屏的三种方案

    本文总结三种用于安卓录屏的解决方案: adb shell命令screenrecord MediaRecorder, MediaProjection MediaProjection , MediaCod ...

  9. Android 添加微信分享三种实现方案

    Android 添加微信分享三种方案 使用android的intent实现应用程序之间的通信,将信息通过intent传递给微信.这种方式的局限性在于 a.只能发送图片,而不是文字或者图片+文字. b. ...

最新文章

  1. Java基础之移位运算,为什么高位补1?
  2. 文件系统与NoSQL分布式存储技术对比
  3. Android6.0 wakelock深入分析
  4. Python地图可视化三大秘密武器
  5. JavaOne 2014 –有关提交的一些初步分析
  6. mysql中起飞到达城市查询_让mysql慢慢起飞 - 初识慢日志
  7. 人工智能芯片与传统芯片的区别
  8. linux man 手册翻译,close (linux man) 翻译
  9. 去掉iframe的水平滚动条而保留垂直滚动条
  10. 创业者如何利用数字经济实现企业升级?
  11. 基于阿里云实现简单的语音识别功能
  12. ext源码阅读 - DomHelper - createHtml,insertHtml
  13. 分布式文件系统(FastDFS+Tengine+fastdfs-nginx-module)
  14. 电气工程师需掌握哪些计算机知识,一名合格电气工程师必须掌握的10个基本技能...
  15. ERP项目组成员及各项目组职责
  16. 机器人油封_机器人油封 机器人减速机 机器人伺服电机油封 KVNOK油封
  17. jenkins+svn+脚本实现CIDI
  18. C++中string类下的begin,end,rbegin,rend的用法
  19. 深度学习(二)——从零自己制作数据集到利用deepNN实现夸张人脸表情的实时监测(tensorflow实现)
  20. 使用 Python 脚本执行国密 sm2 加解密

热门文章

  1. 宿舍管理小程序开发制作功能介绍
  2. fastadmin操作中添加自定义按钮,点击弹出表格
  3. 面试题 请简述vue双向数据绑定原理
  4. java web工程搭建_手把手搭建javaweb项目_手把手javaweb
  5. Leecode:给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数
  6. 【excel导出两级表头实现】
  7. 小白知识:什么是云计算?
  8. 静态内部类的单例模式如何保证线程安全
  9. 推荐3个Python 文本终端 GUI 框架,太酷了
  10. NPOI Excel数据写入及读取