版權聲明:android
本帳號發佈文章均來自公衆號,承香墨影(cxmyDev),版權歸承香墨影全部。bash
未經容許,不得轉載。post
倒計時這種,每秒更新 UI 的需求,應該算是比較常見的了。最多見的場景,就是驗證碼發送超時重試的邏輯,這個邏輯中須要一個倒計時的邏輯去每秒修改 UI ,讓倒計時作到用戶可感知。ui
那麼倒計時的邏輯,須要如何作到極致?spa
一個倒計時,最少要有兩個要求:準、穩。線程
準就是說,一個 2 分鐘的倒計時,就應該執行兩分鐘,穩的意思就是說,每次同步 UI 的更新,都是差很少間隔 1s。3d
倒計時說白了就是一個間隔固定時間去作一件固定任務,這樣的功能,最簡單的就是使用 Handler.postDelayed()
去間隔執行。code
那麼咱們寫一個 CountdownUtils 的類,先看看它的結構。cdn
new CountdownUtils(120).start()複製代碼
看看 Log 輸出的結果,視頻
從 Log 上看,確實是完成了一個倒計時的功能,一秒一秒一直到 0 ,可是這裏爲了觀察準不許,對倒計時執行的完整時間作了一個間隔記錄,看到問題了嗎?一個 120s 的倒計時,卻執行了 124s 左右。
這個問題其實是由於 Handler.postDelayed() 的間隔時長,並非準確的間隔指定的時長,具體何時執行,其實是看線程的調度的。這種總時長差別的問題,換了 Timer 什麼的去實現也是沒法解決的。
這個問題,在一些驗證碼倒計時的場景下,沒有參照事件點,每一個倒計時,偏差幾十毫秒,基本上是用戶無感知的。可是有一些狀況下,例如視頻播放的倒計時,這種有參照的狀況下,幾分鐘的倒計時,偏差幾秒鐘,就是很是明顯的 Bug 了。
這就是不穩,那麼,如何把倒計時作的穩呢?
實現一個倒計時, Android 實際上是提供了對應的支持類的,那就是 CounDownTimer ,它處於 android.os 包下的,徹底能夠實現一個倒計時的邏輯。
咱們先看看它是如何使用的。
繼續運行一下看看 Log 的輸出狀況。
再仔細看看,onTick() 方法回調的參數,是一個 毫秒 爲單位的數值,而這個數值,實際上是有偏差的,可是這個其實也不影響,只須要對其進行四捨五入的運算,就能夠獲得正確的倒計時秒數。
例如:2830 就是 3s,1828 就是 2s。
可是再仔細看看,就能發現問題,若是使用這種方式來處理倒計時的話,你會發現,拿不到 1s 的狀態,會直接 3s - 2s - finish,這個問題,從 Log 上也能夠反應出來。
這就很尷尬了,有沒有參照物,都是一個 Bug,只能先看看 CountDownTimer 的源碼了,它是如何保證總時長的準確的。
既然找到了 CountDownTimer 保證時間準確行的關鍵點,那麼咱們能夠改寫第一個 Demo 的代碼,來解決沒有 1s 狀態的問題。
沒什麼好說的,就是計算這次間隔耗時,而後比 1s 多出來的毫秒值,從下一個 1s 中減去,來糾正間隔時長。
一個倒計時,簡簡單單使用 Handler.postDelayed() 也是沒法保證準和穩的。細節決定成敗,一個倒計時也是能夠作到極致的。