??????? 相信大家在項目里面不少會用到倒計時操作吧稿壁,倒計時功能在我們業(yè)務(wù)開發(fā)中使用概率非常高幽钢,例如用戶操作姿勢錯誤,我們給一個提示傅是,提示是帶有倒計時的對話框匪燕,當(dāng)然你會問為什么不直接用Toast呢?
??????? 確實喧笔,我們可以直接用土司帽驯,但是往往這不是產(chǎn)品想要的,他們覺得沒有交互书闸,體驗很差尼变,再例如我們用戶完成某個任務(wù)也可以通過這種倒計時框給用戶提醒,倒計時操作再android開發(fā)需求很廣泛浆劲,這里就不多說嫌术。
?????? 在andriod中倒計時的實現(xiàn)也有很多種,你可以通過最常用的Handler+Thread方式實現(xiàn)牌借,也可以通過Timer方式實現(xiàn)度气,當(dāng)然也可以通過本章要介紹的Google官方推薦的CountDownTimer來實現(xiàn),當(dāng)然解決問題的方式又很多膨报,不僅僅就這幾種方法,這幾種只是個眾多方法中的代表择示,像Handler實現(xiàn)倒計時還有很多變種栅盲,例如很Message搭配方式谈秫,跟Runnable結(jié)合使用方式等等拟烫,總之硕淑,歸根結(jié)底都是在子線程進行耗時操作,在UI線程進行更新于樟。
那么現(xiàn)在我們分別介紹這幾種不同的方式:
1)通過Handler+Thread/Runnable方式
先上碼再說:
正如大家所見我們在主線程中創(chuàng)建一個Handler,通過handler機制來更新我們的UI,這里更新UI是指我們展示給大家看的倒計時寥袭,這里我只介紹倒計時的邏輯和實現(xiàn)传黄,具體應(yīng)用在什么場景大家自己發(fā)揮吧尝江,你可以展示在一個TextView上炭序,也可以彈出一個對話框當(dāng)作提示,這里我們對倒計時的載體忽略惭聂,大家關(guān)心倒計時的邏輯并根據(jù)情況移植到自己的案例中辜纲。
我們在主線程中(即ui線程)創(chuàng)建一個handler,這里我們用到handler消息機制,不明白的可以去看這篇文章www.reibang.com/p/138363a97da8
在handler中對控件更新內(nèi)容杀糯,這里指秒數(shù)苍苞,再自減向下循環(huán)羹呵,然后通過handler將消息發(fā)送出去,是通過handler.sendEmptyMessageDelayed(0,1)歉铝,第一個參數(shù)是延遲時間太示,第二個參數(shù)是時間間隔先匪,當(dāng)second小于0的時候弃衍,這時候倒計時完畢镜盯,我們就必須取消發(fā)送速缆,通過removeCallbacksAndMessages()方法恩闻,不然handler會內(nèi)存泄漏導(dǎo)致程序崩潰幢尚,就這樣完了尉剩?理茎?管嬉?? 似乎我們還確定什么蚯撩,對胎挎,一開始我們就在handler中處理MessageQueue中的消息呀癣,但是第一條消息來自哪兒项栏? 好像沒找到沼沈,沒錯币厕,這里我省略掉了我們第一條消息這個引子旦装,再次上圖:
這里的show方法大家可以不用關(guān)心阴绢,因為我這里倒計時放在對話彈框里面眨八,屬于對話框的邏輯左电,大家可以調(diào)用new Thread(new MyThread()).start()直接開啟我們的倒計時,這就是handler的實現(xiàn)倒計時段誊,熟悉Handler機制的同學(xué)理解起來應(yīng)該沒問題枕扫。
2)直接通過Handler方式
這種方式跟上一種區(qū)別在于handler是在oncreate()中創(chuàng)建的(initView()在onCreate()方法中)烟瞧,activity創(chuàng)建的時候會調(diào)用生命周期函數(shù)完成其整個生命過程,在onCreate中會創(chuàng)建hanlder强岸,然后通過obtainMessage()創(chuàng)建Message,最后通過sendEmptyMessage()將消息發(fā)送出去蝌箍,這里message我們只是創(chuàng)建但是空的妓盲,因為我們不需要攜帶消息到UI線程悯衬,所以我們向MessageQueue發(fā)送一條新消息筋粗,然后handler進入循環(huán)狀態(tài)娜亿,線程內(nèi)部Looper開始輪詢不斷從MwssageQueue中取出消息分發(fā)給handler處理买决,知道所有消息處理完策州,handler不再發(fā)送消息為止,這個過程業(yè)務(wù)層面的實現(xiàn)也就是handleMessage()中的邏輯藕夫,我們在handler初始化的時候可以設(shè)定一個倒計時時長——mLimitTime毅贮,在oncreate()中就發(fā)送一條空消息讓handler循環(huán)起來滩褥,每一次處理消息時候?qū)r長mLimitTime進行判斷瑰煎,在對應(yīng)的控件上更新當(dāng)前時長,不要忘了mLimitTime--魄健,不斷循環(huán)直到我們時長等于0也就是else流程沽瘦,這里我回調(diào)對話框dismiss()方法析恋,在這個方法里面我們需要removeCallbacksAndMessages()取消我們的handler機制助隧,防止出現(xiàn)內(nèi)存泄漏窟扑,跟方式1邏輯上沒有太大的差別橘霎,主要熟悉handler機制殖属。
不過這種方式我用的是Kotlin實現(xiàn)的外潜,如果第一次接觸Kotlin的可能看起來不是很舒服处窥,但是對于會Java的人來說應(yīng)該不是太大問題滔驾,你也可以根據(jù)這個邏輯用java實現(xiàn)這個倒計時俄讹。
3)Timer倒計時方式
?????? 例外使用Timer和TimerTask也是很簡單哆致,用法很固定,所以大家直接根據(jù)模板調(diào)用就行患膛,首先我們在類初始化的時候創(chuàng)建好Timer和TimerTask摊阀,這個和Handler用法很相似,task的內(nèi)部我們是通過runOnUiThread()方式在ui線程更狀態(tài),循環(huán)邏輯也是差不多胞此,當(dāng)我們倒數(shù)計時長recLen等于0的時候我們就cancel()取消Timer操作臣咖,這和handler的removecallbackandMessage()差不多,后面的Intent大家直接可以忽略豌鹤,這個是針對業(yè)務(wù)的邏輯亡哄,然后準(zhǔn)備工作都完成后,我們在onFinishCreateView()中通過schedule(task,0,1000)開啟這個task蚊惯,這個和使用handler機制中的sendEmptyMessage()作用是一樣的宦焦,這里的onFinishCreateView()方法也是業(yè)務(wù)需求方法,大家可以把task.schedule()放到onCreate()或者onResume()啟動方法中蒲障,開啟任務(wù)并進行循環(huán),直到條件不合理跳出循環(huán),期間每次循環(huán)都更新控件內(nèi)容。
是不是很簡單2笸弧!!!
4)CountDownTimer Google墻裂推薦方式:
那我們來看一看google到底是如何來封裝這一款倒計時的
構(gòu)造方法:
millisInFuture:倒計時時長蹦渣,
countDownInterval:倒計時時間隔
首先會對millisInFuture合理判斷,倒計時不合理就直接finish掉,mStopTimeInFuture=SystemClock.elapsedRealtime()+mMillisInFuture獲取倒計時終止完成時間堪滨,是什么意思呢发笔? 先拿到們系統(tǒng)當(dāng)前時長前计,然后再加上我們倒計時時長伶棒,相當(dāng)于再代碼中對終止時間做了一個標(biāo)記mStopTimeInFuture舅锄,接著看叨襟,是不是出現(xiàn)很熟悉的代碼——sendMessage()右犹,原來CountDownTime內(nèi)部已經(jīng)為我們封裝好了handler機制掂墓,怪不得Google非常推薦得方式啦粹,避免開發(fā)者開發(fā)過程中姿勢使用不對導(dǎo)致內(nèi)存泄漏引發(fā)程序崩潰忍饰,接著繼續(xù)看源碼
這里就是處理消息的邏輯茧吊,首先google為了程序的健壯性和一致性為當(dāng)前倒計時任務(wù)進行枷鎖乳讥,大家看這段代碼:final longmillisLeft=mStopTimeInFuture-SystemClock.elapsedRealtime();? 每次從消息隊列中取出消息都會計算剩下時長告嘲,同樣對剩下時長進行合理判斷错维,有一點需要注意,onTick(millisLeft)這是個啥東西侨嘀,好像是個回調(diào)方法涨共,確實google為我們抽象了兩個比較常用的回調(diào)方法,當(dāng)我們沒執(zhí)行一個時間間隔后,就會調(diào)用這個回調(diào)方法更新我們控件狀態(tài)等操作牧挣,接著看:
沒錯,內(nèi)部不斷循環(huán)發(fā)送消息陆赋,handler的用法主要就是這些沐祷,無非是google替我們封裝好了邏輯嚷闭,同理直到millisLeft等于0回調(diào)onFinish()方法
上面我們將源碼簡單過了一下,下面我們繼續(xù)貼代碼赖临,看看該怎么用:
onFinish()和onTick()方法你可以自由發(fā)揮胞锰,根據(jù)需求來執(zhí)行邏輯,
其實有個更簡單做法兢榨,直接new出一個CountDownTimer()并start這個倒計時就ok了 胜蛉,然后在回調(diào)里面進行UI更新操作,不用在定義一個TimeCount,之所以這樣寫因為擴展性好色乾。
到此,我們介紹的幾種倒計時基本結(jié)束了领突,說來說去無非就是handler的用法以及對其進行的封裝暖璧,還不是很了解handler的寶寶去看一下handler的文章,暫時就先到這了君旦,祝大家周末愉快喲E彀臁!金砍!