最近才开始看的Android音视频开发,觉得里面对MediaPlayer的各种状态讲解的比较详细,做了一下笔记:
Android的MediaPlayer专门用于控制视频/音频的文件以及流的播放,有状态机进行管理,相关的状态周期可由10个状态组成,如下图:
图中的椭圆代表 MediaPlayer 驻留的状态,弧代表播放控制且聚动 MediaPlayer 状态进行过渡.有两种类型的弧,单箭头弧表示的是同步函数调用,双箭头弧表示的是异步函数调用。
从图中,我们能看到MediaPlayer 有下面的一些状态。
ldle状态及End状态
在 MediaPlayer 创建实例或者调用 reset 函数后,播放器就被创建了,这时处于ldle (就 绪)状态,调用 release函数后,就会变成 End(结束)状态,在这两种状态之间的就是 MediaPlayer的生命周期。
Error 状态
在构造一个新MediaPlayer 或者调用reset 函数后,上层应用程序调用的getCurrentPosition、 getVideoHeight 、 getDuration 、 getVideoWidth 、 setAudioStreamType(int)、 setLooping(boolean)、 setVolume(float,float)、 pause、 start、 stop、 seekTo(int)、 prepare、 prepareAsync 这些函数如果会出错。如果调用 reset 函数后再调用它们,用户提供的回调函数OnErrorListener.onError 将触发 MediaPlayer 状态到 Error(错误)状态,所以一旦不再使用 MediaPlayer,就需要调用 release 函数,以便 MediaPlayer 资源得到合理释放。
当 MediaPlayer 处于End(结束)状态时,它将不能再被使用,这时不能再回到 MediaPlayer的其他状态,因为本次生命周期已经终止。
由于支持的音视频格式分辨率过高,输入数据流超时,或者其他各种各样的原因将导致播放失败。在这种错误的条件下,如果用户事先通过setOnErrorListener 注册过OnErrorListener, 当 player 内部调用OnErrorListener.onError 回调函数时,将会返回错误信息。一旦有错误, MediaPlayer 会进入 Error(错误)状态,为了重新使用MediaPlayer,调用 reset 函数,这时将重新恢复到Idle(就绪)状态,所以需要给 MediaPlayer 设置错误监听,出错后就可以从播放器内部返回的信息中找到错误原因。
Initialized 状态
当调用 setDataSource(FileDescriptor)s setDataSource(String)、 setDataSource(Context, Uri)、 setDataSource(FileDescriptor, long, long)其中一个函数时,将传递 MediaPlayer 的 Idle 状态变成 Initialized(初始化)状态,如果 setDataSource 在非 Idle状态时调用,会抛出 IllegalStateException 异常。当重载setDataSource时,需要抛出IlegalArgumentException 和 IOException这两个异常。 5. Prepared 状态
MediaPlayer 有两种途径到达 Prepared 状态,一种是同步方式,另一种是异步方式。同步方式主要使用本地音视频文件,异步方式主要使用网络数据,需要缓冲数据。调用 prepare (同步函数)将传递MediaPlayer 的 Initialized状态变成Prepared状态,或者调用 prepareAsync (异步函数)将传递MediaPlayer 的 Initialized状态变成Preparing状态,最后到Prepared状态。 如果应用层事先注册过setOnPreparedListener ,播放器内部将回调用户设置的 OnPreparedListener 中的 onPrepared 回调函数。注意,Preparing是一个瞬间状态(可理解为时间比较短)。
Started 状态
在 MediaPlayer 进入 Prepared 状态后,上层应用即可设置一些属性,如音视频的音量、 sereenOnWhilePlaying、 looping 等。在播放控制开始之前,必须调用 start 函数并成功返回, MediaPlayer的状态开始由 Prepared状态变成Started状态。当处于 Started状态时,如果用户事先注册过setOnBufferingUpdateListener,播放器内部会开始回调OnBuferingUpdateListener.on BuferingUpdate,这个回调函数主要使应用程序保持跟踪音视频流的 bufering(缓冲) status如果MediaPlayer 已经处于 Started状态,再调用start函数是没有任何作用的。
Paused状态
MediaPlayer在播放控制时可以是Paused (暂停)和Stopped (停止)状态的,且当前的播 放时进度可以被调整,当调用 MediaPlayer.pause函数时,MediaPlayer 开始由 Started状态变成 Paused状态,这个从 Started 状态到Paused状态的过程是瞬间的,反之在播放器内部是异步过程的。在状态更新并调用isPlaying函数前,将有一些耗时。已经缓冲过的数据流,也要耗费数秒。
当start函数从 Paused 状态恢复回来时,playback恢复之前暂停时的位置,接着开始播放,这时MediaPlayer的 Paused状态又变成Started状态。如果MediaPlayer已经处于 Paused状态,这时再调用 pause函数是没有任何作用的,将保持Paused状态。
Stopped 状态
当调用stop 函数时,MediaPlayer 无论正处于Started 、 Paused 、Prepared 或 PlaybackCompleted 中的哪种状态,都将进入 Stopped状态。一旦处于Stopped状态,playback将不能开始,直到重新调用 prepare 或 prepareAsync函数,且处于Prepared 状态时才可以开始。
如果 MediaPlayer 已经处于 Stopped状态了,这时再调用 stop函数是没有任何作用的,将 保持Stopped状态。
在 Seek操作完成后,如果事先在MediaPlayer 注册了setOnSeekCompleteListener,播放器内部将回调OnSeekComplete.onSeekComplete函数。当然seekTo函数也可以在其他状态下被调用,如 Prepared、 Paused 及 PlaybackCompleted 状态。
PlaybackCompleted 状态
当前播放的位置可以通过 getCurrentPosition函数获取,通过 getCurrentPosition函数,可以跟踪播放器的播放进度。 当MediaPlayer 播放到数据流的末尾时,一次播放过程完成。在 MediaPlayer 中事先调用 setLooping(boolean)并设置为true,表示循环播放,MediaPlayer 依然处于Started状态。如果调用setLooping(boolean)并设置为 false(表示不循环播放),并且事先在 MediaPlayer 上注册过setOnCompletionListener,播放器内部将回调OnCompletion.onCompletion 函数,这就表明MediaPlayer 开始进入PlaybackCompleted(播放完成)状态。当处于 PlaybackCompleted 状态时,调用start函数,将重启播放器从头开始播放数据。