<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
關於倒計時可以說我們App開發中常見的一種場景了,比如Splash倒計時跳轉首頁,比如傳送簡訊之後倒計時60秒顯示等等。
關於倒計時的實現方式,大家可能有不同的做法,這裡做一下總結看看你使用的是哪一種呢?
直接上程式碼:
//倒計時的方式一 fun countDownTimer() { var num = 60 timer = 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? = null override fun onDestroy() { super.onDestroy() timer?.cancel() }
沒什麼花活,就是android.os包下面的 CountDownTimer 類的使用。內部實現使用了 Handler 進行封裝。
private var handlerNum = 60 private 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() { @Override public void run() { recLen++; txtView.setText("" + recLen); handler.postDelayed(this, 1000); } public void test(){ handler.postDelayed(runnable, 1000); }
以上是Android的倒計時方案,其實Java的Api也是支援倒計時實現的,比如 Timer 配合 TimerTask 就可以實現簡單的倒計時。
fun countDownTimer2() { var num = 60 val timer = Timer() val timeTask = object : TimerTask() { override fun run() { num-- YYLogUtils.w("當時計數:" + num) if (num < 0) { timer.cancel() } } } timer.schedule(timeTask, 1000, 1000) }
我們可以通過Thread的sleep方法來實現倒計時,不過由於是子執行緒我們不能更新UI,所以還是需要配合Handler實現。
private var mThread: Thread = Thread(this) private var mflag = false private var mThreadNum = 60 override fun run() { while (mflag && mThreadNum >= 0) { try { Thread.sleep(1000) } catch (e: InterruptedException) { e.printStackTrace() } val message = Message.obtain() message.what = 1 message.arg1 = mThreadNum handler.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 = true if (mThread.state == Thread.State.TERMINATED) { mThread = Thread(this@DemoCountDwonActivity) if (mThreadNum == -1) mThreadNum = 60 mThread.start() } else { mThread.start() } } else { mflag = false } } override fun onDestroy() { super.onDestroy() mflag = false }
這裡的銷燬執行緒我沒有使用stop方法,已經不推薦我們使用,我們使用flag來判斷即可。
這樣的執行緒並不是我們想要的,我們通常並不會直接new Thread 來進行一些邏輯操作,比如我們可能使用RxJava框架,通過操作符的方式來進行倒計時。
比我們倒計時4秒之後跳轉頁面的實現:
val SHOTDOWN_TIME = 4 val mDisposables : Disposable? = null Observable.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物件在頁面銷燬的時候釋放,以免記憶體洩露,有沒有簡單一點方式?
上面的方法都需要銷燬資源,好麻煩,能不能自動取消?協程不就行了。
是的 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 { // 在這裡 更新值來顯示到UI next(it) } } }
使用:
fun startCountDown() { var timeDownScope: CoroutineScope? = null countDown( time = 60, start = { timeDownScope = it YYLogUtils.e("開始") }, end = { YYLogUtils.e("結速倒計時") toast("結速倒計時") }, next = { YYLogUtils.w("當時計數:" + it) if (it == 50) { timeDownScope?.cancel() } }) }
無需onDestory中銷燬資源,如果想自由手動的控制倒計時,我們再start的高階函數中接收父協程的上下文物件即可自動控制。使用起來也是超級簡單。
倒計時的實現是我們常用的功能,如果你的專案是Kotlin構建的,那麼我建議使用Flow來實現這種功能,使用擴充套件函數進行封裝,使用起來更加的簡單。
如果你們專案是Java語言實現的,那麼同樣的可以選擇一種方式進行一個工具類的封裝,也能達到同樣的效果,只是記得需要在onDestory中銷燬資源哦。
到此這篇關於Android實現倒計時的方案梳理的文章就介紹到這了,更多相關Android倒計時方案內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45