相信大家在專案裡面不少會用到倒數計時操作吧,倒數計時功能在我們業務開發中使用概率非常高,例如使用者操作姿勢錯誤,我們給一個提示,提示是帶有倒數計時的對話方塊,當然你會問為什麼不直接用Toast呢?
確實,我們可以直接用土司,但是往往這不是產品想要的,他們覺得沒有互動,體驗很差,再例如我們使用者完成某個任務也可以通過這種倒數計時框給使用者提醒,倒數計時操作再android開發需求很廣泛,這裡就不多說。
在andriod中倒數計時的實現也有很多種,你可以通過最常用的Handler+Thread方式實現,也可以通過Timer方式實現,當然也可以通過本章要介紹的Google官方推薦的CountDownTimer來實現,當然解決問題的方式又很多,不僅僅就這幾種方法,這幾種只是個眾多方法中的代表,像Handler實現倒數計時還有很多變種,例如很Message搭配方式,跟Runnable結合使用方式等等,總之,歸根結底都是在子執行緒進行耗時操作,在UI執行緒進行更新。
那麼現在我們分別介紹這幾種不同的方式:
1)通過Handler+Thread/Runnable方式
先上碼再說:
正如大家所見我們在主執行緒中建立一個Handler,通過handler機制來更新我們的UI,這裡更新UI是指我們展示給大家看的倒數計時,這裡我只介紹倒數計時的邏輯和實現,具體應用在什麼場景大家自己發揮吧,你可以展示在一個TextView上,也可以彈出一個對話方塊當作提示,這裡我們對倒數計時的載體忽略,大家關心倒數計時的邏輯並根據情況移植到自己的案例中。
我們在主執行緒中(即ui執行緒)建立一個handler,這裡我們用到handler訊息機制,不明白的可以去看這篇文章www.jianshu.com/p/138363a97…
在handler中對控制元件更新內容,這裡指秒數,再自減向下迴圈,然後通過handler將訊息傳送出去,是通過handler.sendEmptyMessageDelayed(0,1),第一個引數是延遲時間,第二個引數是時間間隔,當second小於0的時候,這時候倒數計時完畢,我們就必須取消傳送,通過removeCallbacksAndMessages()方法,不然handler會記憶體洩漏導致程式崩潰,就這樣完了???
似乎我們還確定什麼,對,一開始我們就在handler中處理MessageQueue中的訊息,但是第一條訊息來自哪兒?
好像沒找到,沒錯,這裡我省略掉了我們第一條訊息這個引子,再次上圖:
這裡的show方法大家可以不用關心,因為我這裡倒數計時放在對話彈框裡面,屬於對話方塊的邏輯,大家可以呼叫new
Thread(new
MyThread()).start()直接開啟我們的倒數計時,這就是handler的實現倒數計時,熟悉Handler機制的同學理解起來應該沒問題。
2)直接通過Handler方式
這種方式跟上一種區別在於handler是在oncreate()中建立的(initView()在onCreate()方法中),activity建立的時候會呼叫生命週期函式完成其整個生命過程,在onCreate中會建立hanlder,然後通過obtainMessage()建立Message,最後通過sendEmptyMessage()將訊息傳送出去,這裡message我們只是建立但是空的,因為我們不需要攜帶訊息到UI執行緒,所以我們向MessageQueue傳送一條新訊息,然後handler進入迴圈狀態,執行緒內部Looper開始輪詢不斷從MwssageQueue中取出訊息分發給handler處理,知道所有訊息處理完,handler不再傳送訊息為止,這個過程業務層面的實現也就是handleMessage()中的邏輯,我們在handler初始化的時候可以設定一個倒數計時時長——mLimitTime,在oncreate()中就傳送一條空訊息讓handler迴圈起來,每一次處理訊息時候對時長mLimitTime進行判斷,在對應的控制元件上更新當前時長,不要忘了mLimitTime–,不斷迴圈直到我們時長等於0也就是else流程,這裡我回撥對話方塊dismiss()方法,在這個方法裡面我們需要removeCallbacksAndMessages()取消我們的handler機制,防止出現記憶體洩漏,跟方式1邏輯上沒有太大的差別,主要熟悉handler機制。
不過這種方式我用的是Kotlin實現的,如果第一次接觸Kotlin的可能看起來不是很舒服,但是對於會Java的人來說應該不是太大問題,你也可以根據這個邏輯用java實現這個倒數計時。
3)Timer倒數計時方式
例外使用Timer和TimerTask也是很簡單,用法很固定,所以大家直接根據模板呼叫就行,首先我們在類初始化的時候建立好Timer和TimerTask,這個和Handler用法很相似,task的內部我們是通過runOnUiThread()方式在ui執行緒更狀態,迴圈邏輯也是差不多,當我們倒數計時長recLen等於0的時候我們就cancel()取消Timer操作,這和handler的removecallbackandMessage()差不多,後面的Intent大家直接可以忽略,這個是針對業務的邏輯,然後準備工作都完成後,我們在onFinishCreateView()中通過schedule(task,0,1000)開啟這個task,這個和使用handler機制中的sendEmptyMessage()作用是一樣的,這裡的onFinishCreateView()方法也是業務需求方法,大家可以把task.schedule()放到onCreate()或者onResume()啟動方法中,開啟任務並進行迴圈,直到條件不合理跳出迴圈,期間每次迴圈都更新控制元件內容。
是不是很簡單!!!!
4)CountDownTimer Google牆裂推薦方式:
那我們來看一看google到底是如何來封裝這一款倒數計時的
構造方法:
millisInFuture:倒數計時時長,
countDownInterval:倒數計時時間隔
首先會對millisInFuture合理判斷,倒數計時不合理就直接finish掉,mStopTimeInFuture=SystemClock.elapsedRealtime()+mMillisInFuture獲取倒數計時終止完成時間,是什麼意思呢?
先拿到們系統當前時長,然後再加上我們倒數計時時長,相當於再程式碼中對終止時間做了一個標記mStopTimeInFuture,接著看,是不是出現很熟悉的程式碼——sendMessage(),原來CountDownTime內部已經為我們封裝好了handler機制,怪不得Google非常推薦得方式,避免開發者開發過程中姿勢使用不對導致記憶體洩漏引發程式崩潰,接著繼續看原始碼
這裡就是處理訊息的邏輯,首先google為了程式的健壯性和一致性為當前倒數計時任務進行枷鎖,大家看這段程式碼:final
longmillisLeft=mStopTimeInFuture-SystemClock.elapsedRealtime();
每次從訊息佇列中取出訊息都會計算剩下時長,同樣對剩下時長進行合理判斷,有一點需要注意,onTick(millisLeft)這是個啥東西,好像是個回撥方法,確實google為我們抽象了兩個比較常用的回撥方法,當我們沒執行一個時間間隔後,就會呼叫這個回撥方法更新我們控制元件狀態等操作,接著看:
沒錯,內部不斷迴圈傳送訊息,handler的用法主要就是這些,無非是google替我們封裝好了邏輯,同理直到millisLeft等於0回撥onFinish()方法
上面我們將原始碼簡單過了一下,下面我們繼續貼程式碼,看看該怎麼用:
onFinish()和onTick()方法你可以自由發揮,根據需求來執行邏輯,
其實有個更簡單做法,直接new出一個CountDownTimer()並start這個倒數計時就ok了 ,然後在回撥裡面進行UI更新操作,不用在定義一個TimeCount,之所以這樣寫因為擴充套件性好。
到此,我們介紹的幾種倒數計時基本結束了,說來說去無非就是handler的用法以及對其進行的封裝,還不是很瞭解handler的寶寶去看一下handler的文章,暫時就先到這了,祝大家週末愉快喲!!!