美文网首页Android开发Android技术知识Android开发部落
强迫症的研究——MediaPlayer播放进度条的优化

强迫症的研究——MediaPlayer播放进度条的优化

作者: eclipse_xu | 来源:发表于2015-11-13 16:51 被阅读2399次

    强迫症的研究——MediaPlayer播放进度条的优化

    如何做一个优美、流畅而且准确的播放进度条,也许很多人觉得很简单,但实际上,这个问题在大部分时间都被忽略了。

    计时方式的比较

    • 计时方式——主线程中使用Handler

      -- 这种方式最简单,在主线程中通过handler.postDealyed(……, 1000),并在onHandleMessage中继续post消息,这样就实现了每隔1000ms进行一次消息循环。

    • 计时方式——使用单独计时线程

      -- 单独创建一个计时线程,每秒发出time tick事件,主线程通过该事件来更新进度。这种方式比较麻烦,但是不麻烦怎么装逼呢?

      如何高雅、准确的实现

      对于Handler方式

    • 自身误差

    这种方式下,如果使用handler.postDealyed(……, 1000)方式来进行每秒的计时,是不准确的,是的,有很大误差,误差的原因在于在你收到消息,到你重新发出handler.postDealyed的时间,并不是瞬间完成的,这里面有很多逻辑处理的时间,即使没有逻辑处理的时间,handler本身也是耗损性能的,所以消息并不可能按照理想的1000延迟来进行发送,这就导致了误差的累积。

    • 线程调度误差

    我们知道,当音乐线程启动,到handler发出消息,这一段时间内,存在进程调度或者其它逻辑的耗时操作,导致这两个时间并不是同时发生的。所以,我们每次在post的时候,都需要对计时进行下补偿,但是,怎么做呢?

    对于Handler方式的优化

    我们知道,Android中有很多计时的控件,首先想到的是DigitalClock,结果发现已经废弃,好吧,看被什么替换了,OK,发现了TextClock,代码多了不少,感觉更牛逼了。我们直接看他是怎么处理这个问题的:

    同样是通过程序员的嗅觉找到这里:

        private final Runnable mTicker = new Runnable() {
            public void run() {
                onTimeChanged();
    
                long now = SystemClock.uptimeMillis();
                long next = now + (1000 - now % 1000);
    
                getHandler().postAtTime(mTicker, next);
            }
        };
    

    哎呦,有点意思,我们之前是通过postDelay来触发消息事件的,但这里系统使用了postAtTime,这是为什么呢?很自然我们会想到前面两行代码,其实也不用想太多,你代个值进去试下就知道了,假如now取出来是1200,那么next = 1200 + (1000 - 1200 % 1000)也就是next= 2000。你看,虽然我们前一次本该在1000触发的事件,被各种逻辑延迟到1200,那么如果你用postDelay,这个延迟就被累积了,但如果用这种方式,误差就被补偿了。

    我们就叫他误差补偿算法吧~

    对于单独计时线程方式

    对于单独计时的线程,由于时间点的触发事件和主线程已经分开了,计时线程就不会受主线程逻辑的阻塞了,所以,只要保证开始时对起始时间差进行下同步就OK了。

    对于单独计时线程方式的优化

    其实对于单独计时线程来说,已经没有什么好优化的了,而且优点还能再列举不少:

    1. 计时逻辑与UI逻辑分离,方便拓展
    2. 计时准确,可以将计时线程封装,暴露接口,方便拓展
    3. 解耦、装逼

    如果你还要再进一步优化的话,可以在计时的时候,使用时间差的方式来统计,虽然没什么乱用。

    相关文章

      网友评论

        本文标题:强迫症的研究——MediaPlayer播放进度条的优化

        本文链接:https://www.haomeiwen.com/subject/ctfkhttx.html