強(qiáng)迫癥的研究——MediaPlayer播放進(jìn)度條的優(yōu)化
如何做一個(gè)優(yōu)美座菠、流暢而且準(zhǔn)確的播放進(jìn)度條,也許很多人覺得很簡(jiǎn)單,但實(shí)際上劈愚,這個(gè)問題在大部分時(shí)間都被忽略了。
計(jì)時(shí)方式的比較
-
計(jì)時(shí)方式——主線程中使用Handler
-- 這種方式最簡(jiǎn)單闻妓,在主線程中通過handler.postDealyed(……, 1000)菌羽,并在onHandleMessage中繼續(xù)post消息,這樣就實(shí)現(xiàn)了每隔1000ms進(jìn)行一次消息循環(huán)由缆。
-
計(jì)時(shí)方式——使用單獨(dú)計(jì)時(shí)線程
-- 單獨(dú)創(chuàng)建一個(gè)計(jì)時(shí)線程注祖,每秒發(fā)出time tick事件,主線程通過該事件來更新進(jìn)度均唉。這種方式比較麻煩是晨,但是不麻煩怎么裝逼呢?
如何高雅舔箭、準(zhǔn)確的實(shí)現(xiàn)
對(duì)于Handler方式
自身誤差
這種方式下罩缴,如果使用handler.postDealyed(……, 1000)方式來進(jìn)行每秒的計(jì)時(shí),是不準(zhǔn)確的层扶,是的箫章,有很大誤差,誤差的原因在于在你收到消息镜会,到你重新發(fā)出handler.postDealyed的時(shí)間檬寂,并不是瞬間完成的,這里面有很多邏輯處理的時(shí)間戳表,即使沒有邏輯處理的時(shí)間桶至,handler本身也是耗損性能的,所以消息并不可能按照理想的1000延遲來進(jìn)行發(fā)送匾旭,這就導(dǎo)致了誤差的累積镣屹。
- 線程調(diào)度誤差
我們知道,當(dāng)音樂線程啟動(dòng)季率,到handler發(fā)出消息野瘦,這一段時(shí)間內(nèi),存在進(jìn)程調(diào)度或者其它邏輯的耗時(shí)操作,導(dǎo)致這兩個(gè)時(shí)間并不是同時(shí)發(fā)生的鞭光。所以吏廉,我們每次在post的時(shí)候,都需要對(duì)計(jì)時(shí)進(jìn)行下補(bǔ)償惰许,但是席覆,怎么做呢?
對(duì)于Handler方式的優(yōu)化
我們知道汹买,Android中有很多計(jì)時(shí)的控件佩伤,首先想到的是DigitalClock,結(jié)果發(fā)現(xiàn)已經(jīng)廢棄晦毙,好吧生巡,看被什么替換了,OK见妒,發(fā)現(xiàn)了TextClock孤荣,代碼多了不少,感覺更牛逼了须揣。我們直接看他是怎么處理這個(gè)問題的:
同樣是通過程序員的嗅覺找到這里:
private final Runnable mTicker = new Runnable() {
public void run() {
onTimeChanged();
long now = SystemClock.uptimeMillis();
long next = now + (1000 - now % 1000);
getHandler().postAtTime(mTicker, next);
}
};
哎呦盐股,有點(diǎn)意思,我們之前是通過postDelay來觸發(fā)消息事件的耻卡,但這里系統(tǒng)使用了postAtTime疯汁,這是為什么呢?很自然我們會(huì)想到前面兩行代碼卵酪,其實(shí)也不用想太多幌蚊,你代個(gè)值進(jìn)去試下就知道了,假如now取出來是1200溃卡,那么next = 1200 + (1000 - 1200 % 1000)也就是next= 2000霹肝。你看,雖然我們前一次本該在1000觸發(fā)的事件塑煎,被各種邏輯延遲到1200,那么如果你用postDelay臭蚁,這個(gè)延遲就被累積了最铁,但如果用這種方式,誤差就被補(bǔ)償了垮兑。
我們就叫他誤差補(bǔ)償算法吧~
對(duì)于單獨(dú)計(jì)時(shí)線程方式
對(duì)于單獨(dú)計(jì)時(shí)的線程冷尉,由于時(shí)間點(diǎn)的觸發(fā)事件和主線程已經(jīng)分開了,計(jì)時(shí)線程就不會(huì)受主線程邏輯的阻塞了系枪,所以雀哨,只要保證開始時(shí)對(duì)起始時(shí)間差進(jìn)行下同步就OK了。
對(duì)于單獨(dú)計(jì)時(shí)線程方式的優(yōu)化
其實(shí)對(duì)于單獨(dú)計(jì)時(shí)線程來說,已經(jīng)沒有什么好優(yōu)化的了雾棺,而且優(yōu)點(diǎn)還能再列舉不少:
- 計(jì)時(shí)邏輯與UI邏輯分離膊夹,方便拓展
- 計(jì)時(shí)準(zhǔn)確,可以將計(jì)時(shí)線程封裝捌浩,暴露接口放刨,方便拓展
- 解耦、裝逼
如果你還要再進(jìn)一步優(yōu)化的話尸饺,可以在計(jì)時(shí)的時(shí)候进统,使用時(shí)間差的方式來統(tǒng)計(jì),雖然沒什么亂用浪听。