Android MediaPlayer的生命周期

fmms 13年前
     <p>下面图表表现出来生命周期和MediaPlayer类的控制操作,椭圆体描述了MediaPlayer 类的状态,弧线描述了重放控制的运作,有两种箭头,单箭头的弧线代表同步方法的调用,爽箭头代表异步方法的调用。</p>    <p> <br />    <img alt="Android MediaPlayer的生命周期" src="https://simg.open-open.com/show/542c32265b3c6f201e5cb3032f52bdd6.gif" width="554" height="677" /></p>    <p>从这个图我们可以看出MediaPlayer类有如下的状态:</p>    <p>l<strong> 当一个 MediaPlayer类 刚用<span style="font-family:Times New Roman;">new</span><span style="font-family:宋体;">或者在</span><span style="font-family:Times New Roman;">reset()</span><span style="font-family:宋体;">调用后创建,这时处于空闲状态,在</span><a>release()</a> 调用后则处于结束状态,在这两个状态之间就是MediaPlaye的生命周期。</strong></p>    <p>Ø 新创建的MediaPlayer类和调用reset()<span style="font-family:宋体;">后的</span>MediaPlayer类,有着很微妙但很重要的区别:</p>    <p>在空闲状态调用诸如<a>getCurrentPosition()</a>, <a>getDuration()</a>, <a>getVideoHeight()</a>, <a>getVideoWidth()</a>, <a>setAudioStreamType(int)</a>,<a>setLooping(boolean)</a>, <a>setVolume(float, float)</a>, <a>pause()</a>, <a>start()</a>, <a>stop()</a>, <a>seekTo(int)</a>, <a>prepare()</a> or <a>prepareAsync()</a>会报错。如果这些方法在MediaPlayer类正确创建以后,内部播放组件和类的状态变化不能够调用回调方法OnErrorListener.onError() 。但是,这些方法在reset()<span style="font-family:宋体;">后</span>被正确调用的话,内部播放组件就会调用用户提供的回调方法OnErrorListener.onError(),并且类的状态也会转为Error 状态。</p>    <p>Ø 一旦MediaPlayer类很长时间不被用到,则立即调用release()<span style="font-family:宋体;">,使与</span>MediaPlayer类关联的内部播放组件所用到的资源能够立即被释放。 一旦MediaPlayer类处于end<span style="font-family:宋体;">状态,那样的话</span>MediaPlayer类就无法在被用到了,也不能够回到其他任何状态。</p>    <p>Ø 此外,MediaPlayer类用new<span style="font-family:宋体;">创建处于空闲状态,当用</span><span style="font-family:Times New Roman;">create</span><span style="font-family:宋体;">创建时</span>MediaPlayer类不在空闲状态,事实上当成功调用create<span style="font-family:宋体;">方法调用时,这个对象已经处于</span>Prepared 状态了。</p>    <p>l<strong> 总之,一些播放控制操作会失败是有很多原因的,比如不支持的audio/video格式,不完整的audio/video,分 辨率太高,流超时等等。因此在这些情况下,错误报告和恢复很是重要。通常在无效的状态下调用一个播放控制会导致程序错误。在所有错误的情况下,内部播放组 件调用用户提供的OnErrorListener.onError() 方法,前提是OnErrorListener()被事先用<a>setOnErrorListener(android.media.MediaPlayer.OnErrorListener)</a>注册过。</strong></p>    <p>Ø 一旦错误发生记录错误是很重要的,MediaPlayer类进入Error 状态,即使error监听病没有在应用中注册。</p>    <p>Ø 为了重新使用在错误状态的MediaPlayer类和从错误中恢复,可以调用reset()<span style="font-family:宋体;">恢复这个类到空闲状态。</span></p>    <p>Ø 在应用中注册OnErrorListener去发现内部播放组件的错误通知是很好的程序设计惯例。</p>    <p>Ø 抛出IllegalStateException去防止程序错误:如调用prepare()<span style="font-family:宋体;">和</span><span style="font-family:Times New Roman;">prepareAsync(),</span><span style="font-family:宋体;">或者在无效超载状态调用</span><span style="font-family:Times New Roman;">setDataSource().</span></p>    <p><strong>l MediaPlayer类在播放之前要首先进入Prepared状态,有两种方法可以到达Prepared状态(异步方法和同步方法)。</strong></p>    <p>一旦调用prepare()<span style="font-family:宋体;">方法,类就进入</span>Prepared状态,调用prepareAsync()<span style="font-family:宋体;">方法</span>,直到处于休息状态内部播放组件完成准备工作之前类一直处于Preparing状态。当准备工作完成或者调用prepare()<span style="font-family:宋体;">时,内部播放组件会调用用户提供的回调方法:</span>OnPreparedListener接口的onPrepared() 方法,前提是OnPreparedListener 被事先用<a>setOnPreparedListener(android.media.MediaPlayer.OnPreparedListener)</a> 注册)这时类进入Prepared状态。</p>    <p><strong>l 当调用start()<span style="font-family:宋体;">方法成功后,</span>MediaPlayer类进入Started状态。</strong></p>    <p>内部播放组件会调用OnBufferingUpdateListener.onBufferingUpdate() 回调方法,前提是</p>    <p>OnBufferingUpdateListener被事先用<a href="/misc/goto?guid=4959517543959692894">setOnBufferingUpdateListener(OnBufferingUpdateListener)</a>注册。这个回调方法允许应用跟踪缓存状态。</p>    <p><strong>l 当调用<span style="font-family:Times New Roman;">seekTo(int),</span><span style="font-family:宋体;">播放的位置就可以被调整。</span></strong></p>    <p>Ø 调用<span style="font-family:Times New Roman;">seekTo(int)</span><span style="font-family:宋体;">时,实际的寻求工作需要一段时间去完成,特别是视频或者是音频正在播放的时候。当实际的寻求工作完成时会调用</span>OnSeekComplete.onSeekComplete(), 如果OnSeekCompleteListener提前用<a>setOnSeekCompleteListener(OnSeekCompleteListener)</a>.注册过。</p>    <p>Ø 需要注意的是,seekTo(int)<span style="font-family:宋体;">可以在其他的状态调用,例如</span> Prepared, Paused andPlaybackCompleted s这些状态。</p>    <p>Ø 此外,用<a>getCurrentPosition()</a>,方法可以找到当前的播放位置。这个对应用很有帮助,例如音乐播放器需要跟踪播放进度的时候。</p>    <p><strong>l 当播放到达数据流的末尾,播放就完成了。</strong></p>    <p>Ø 如果循环模式设置了<a href="/misc/goto?guid=4959517544044058723">setLooping(ture)</a>,那么MediaPlayer类保持Started状态。</p>    <p>Ø 如果循环模式设置为false,播放组件就会调用OnCompletion.onCompletion(),前提是OnCompletionListener提前用 <a href="/misc/goto?guid=4959517544120520668">setOnCompletionListener(OnCompletionListener)</a>注册过,这时类进入PlaybackCompleted 状态。</p>    <p>Ø 当进入PlaybackCompleted 状态,调用start()<span style="font-family:宋体;">方法,就会在音频和视频源的开头重新开始播放。</span></p>