Android實現(xiàn)一個完美的倒計時功能
一. 已有倒計時方案存在的問題
在開發(fā)倒計時功能時往往我們會為了方便直接使用CountDownTimer或者使用Handler做延時來實現(xiàn),當然CountDownTimer內(nèi)部封裝也是使用的Handler。
如果只是做次數(shù)很少的倒計時或者不需要精確的倒計時邏輯那倒沒關(guān)系,比如說我只要倒計時10秒,或者我大概5分鐘請求某個接口
但是如果是需要做精確的倒計時操作,比如說手機發(fā)送驗證碼60秒,那使用現(xiàn)有的倒計時方案就會存在問題??赡苡行┡笥褯]有注意到這一點,下面我們就來簡單分析一下現(xiàn)有倒計時的問題。
1. CountDownTimer
這個可能是用得最多的,因為方便嘛。但其實倒計時每一輪倒計時完之后都是存在誤差的,如果看過CountDownTimer的源碼你就會知道,他的內(nèi)部是有做校準操作的。(源碼很簡單這里就不分析了)
但是如果你認真的測試過CountDownTimer,你就會發(fā)現(xiàn),即便它內(nèi)部有做校準操作,他的沒一輪都是有偏差,只是他最后一次倒計時完之后的總共時間和開始倒計時的時間相比沒偏差。
什么意思呢,意思就是1秒,2.050秒,3.1秒......,這樣的每輪偏差,導致他會出現(xiàn)10.95秒,下一次12秒的情況,那它的回調(diào)中如果你直接做取整就會出現(xiàn)少一秒的情況,但實際是沒少的。
這只是其中的一個問題,你可以不根據(jù)它的回調(diào)做展示,自己用一個整形累加做展示也能解決。但是他還有個問題,有概率直接出現(xiàn)跳秒,就是比如3秒,下次直接5秒,這是實際的跳秒,是少了一次回調(diào)的那種。
跳秒導致你如果直接使用它可能會大問題,你可能自測的時候沒發(fā)現(xiàn),到時一上線應用在用戶那概率跳秒,那就蛋疼了。
2. Handler
不搞這么多花里胡哨的,直接使用Handler來實現(xiàn),會有什么問題。
因為直接使用handler來實現(xiàn),沒有校準操作,每次循環(huán)會出現(xiàn)幾毫秒的誤差,雖然比CountDownTimer的十幾毫秒的誤差要好,但是在基數(shù)大的倒計時情況下誤差會累計,導致最終結(jié)果和現(xiàn)實時間差幾秒誤差,時間越久,誤差越大
3. Timer
直接使用Timer也一樣,只不過他每輪的誤差更小,幾輪才有1毫秒的誤差,但是沒有校準還是會出現(xiàn)誤差累計,時間越久誤差越大。
二. 自己封裝倒計時
既然無法直接使用原生的,那我們就自己做一個。
我們基于Handler進行封裝,從上面可以看出主要為了解決兩個問題,時間校準和跳秒。自己寫一個CountDownTimer
public class CountDownTimer {
private int mTimes;
private int allTimes;
private final long mCountDownInterval;
private final Handler mHandler;
private OnTimerCallBack mCallBack;
private boolean isStart;
private long startTime;
public CountDownTimer(int times, long countDownInterval){
this.mTimes = times;
this.mCountDownInterval = countDownInterval;
mHandler = new Handler();
}
public synchronized void start(OnTimerCallBack callBack){
this.mCallBack = callBack;
if (isStart || mCountDownInterval <= 0){
return;
}
isStart = true;
if (callBack != null){
callBack.onStart();
}
startTime = SystemClock.elapsedRealtime();
if (mTimes <= 0){
finishCountDown();
return;
}
allTimes = mTimes;
mHandler.postDelayed(runnable, mCountDownInterval);
}
private final Runnable runnable = new Runnable() {
@Override
public void run() {
mTimes--;
if (mTimes > 0){
if (mCallBack != null){
mCallBack.onTick(mTimes);
}
long nowTime = SystemClock.elapsedRealtime();
long delay = (nowTime - startTime) - (allTimes - mTimes) * mCountDownInterval;
// 處理跳秒
while (delay > mCountDownInterval){
mTimes --;
if (mCallBack != null){
mCallBack.onTick(mTimes);
}
delay -= mCountDownInterval;
if (mTimes <= 0){
finishCountDown();
return;
}
}
mHandler.postDelayed(this, 1000 - delay);
}else {
finishCountDown();
}
}
};
private void finishCountDown(){
if (mCallBack != null){
mCallBack.onFinish();
}
isStart = false;
}
public void cancel(){
mHandler.removeCallbacksAndMessages(null);
isStart = false;
}
public interface OnTimerCallBack{
void onStart();
void onTick(int times);
void onFinish();
}
}
思路就是在倒計時開始前獲取一次SystemClock.elapsedRealtime(),沒輪倒計時再獲取一次SystemClock.elapsedRealtime()相減得到誤差,根據(jù)delay校準。然后使用while循壞來處理跳秒的操作,與原生的CountDownTimer不同,這里如果跳了多少秒,就會返回多少次回調(diào)。
總結(jié)
到此這篇關(guān)于利用Android實現(xiàn)一個完美的倒計時功能的文章就介紹到這了,更多相關(guān)Android倒計時功能內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android登陸界面實現(xiàn)清除輸入框內(nèi)容和震動效果
這篇文章主要介紹了Android登陸界面實現(xiàn)清除輸入框內(nèi)容和震動效果,感興趣的小伙伴們可以參考一下2015-12-12
android studio實現(xiàn)簡單的計算器(無bug)
這篇文章主要為大家詳細介紹了android studio實現(xiàn)簡單計算器,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-08-08
Android位圖(圖片)加載引入的內(nèi)存溢出問題詳細解析
Android在加載大背景圖或者大量圖片時,常常致使內(nèi)存溢出,下面這篇文章主要給大家介紹了關(guān)于Android位圖(圖片)加載引入的內(nèi)存溢出問題的相關(guān)資料,需要的朋友可以參考下2022-12-12
Android自定義view之利用drawArc方法實現(xiàn)動態(tài)效果(思路詳解)
這篇文章主要介紹了Android自定義view之利用drawArc方法實現(xiàn)動態(tài)效果,drawArc方法包含了五個參數(shù),具體細節(jié)在本文中給大家提到過,需要的朋友可以參考下2021-08-08
Android開發(fā)之5.0activity跳轉(zhuǎn)時共享元素的使用方法
下面小編就為大家分享一篇Android開發(fā)之5.0activity跳轉(zhuǎn)時共享元素的使用方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-01-01

