??????? 相信大家在項目里面不少會用到倒計時操作吧,倒計時功能在我們業務開發中使用概率非常高,例如用戶操作姿勢錯誤,我們給一個提示,提示是帶有倒計時的對話框,當然你會問為什么不直接用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.lxweimin.com/p/138363a97da8
在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()啟動方法中,開啟任務并進行循環,直到條件不合理跳出循環,期間每次循環都更新控件內容。
是不是很簡單?。。。?/p>
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的文章,暫時就先到這了,祝大家周末愉快喲?。。?/p>