注:本文参照google apis:https://developer.android.com/reference/android/media/MediaPlayer.html
MediaPlayer类可用于控制音频/视频文件和流的播放或回放(playback)。
1.状态图:
音频/视频文件和流的播放控制是使用一个状态机进行管理。下图显示了生命周期,并支持播放控制操作驱动的MediaPlayer对象的状态。椭圆表示一个MediaPlayer对象可以驻留在的状态。所述弧线表示驱动对象的状态过渡的重放控制操作。有两种类型的弧线。具有单箭头头部的弧线表示同步方法调用,而那些与双箭头表示异步方法调用。
而依据上图分析mediaPlayer的所有状态:
(1)MediaPlayer被创建new方法或者在reset方法调用之后,它处于空闲状态(Idle);release()方法被调用的时候,处于结束状态(end);这两种状态之间是mediaPlayer的生命周期。
①创建一个新的MediaPlayer对象,通过new()实现和创建了MediaPlayer对象之后,调用了reset(),这之间有一些微妙但是非常重要的区别。
在以上两种空闲状态的情况下,一些编程错误会调用这些方法: getCurrentPosition(), getDuration(), getVideoHeight(),getVideoWidth(), setAudioStreamType(int), setLooping(boolean), setVolume(float, float), pause(), start(), stop(), seekTo(int),prepare() or prepareAsync() 。
区别:
如果其中的任何一个方法,在MediaPlayer构造(new方法)之后,立即调用,用户所提供的错误回调方法OnErrorListener.onError()将不会被播放引擎回调同时对象的状态也保持不变,即保持Idle状态。
但是如果这些方法是在reset()方法之后调用,用户所提供的内部播放引擎的回调,会被调用。而且MediaPlayer的对象状态也会被转换成Error状态。
②建议是这样的,一旦MediaPlayer对象,不再使用。立即调用release()方法,这样,和MediaPlayer关联的播放引擎所使用的资源能得到立即释放。这些资源可能包括单一的硬件硬件加速组件。调用release()失败可能导致后续的MediaPlayer对象实例去依靠软件实现或失败
(这句不是很理解)。一旦MediaPlayer对象在End状态。它将不能再被使用,同时也没有任何方式让它重回到其它状态。
③此外,MediaPlayer对象通过new的方式创建是处在空闲状态(Idle).当这些创建是通过某个重载的create()方法创建则不是在空闲(idle)状态。如果通过create()方法成功创建的MediaPlayer处在准备完成Prepared状态。
一句话总结:
不在使用的MediaPlayer对象,要即时释放,调用release方法。
(2)通常情况下播放控制操作可能由于多种原因而失败,比如不支持的音频视频格式,分辨率过高,流超时,等等。因此错误报告和恢复在这种情况下的一个重要的问题。有时,由于程序错误,也有可能在一些无效状态下调用回放(播放)操作。在所有的这些错误的情况下,内部播放引擎会调用用户提供的OnErrorListener.onError(),前提是用户事先已经通过setOnErrorListener方法设置过一个OnErrorListener。
①一个重要的提示,一旦一个错误发生,MediaPlayer对象进入Error状态,即使没有OnErrorListener被注册。
②为了重新使用出于Error状态的MediaPlayer对象和从Error状态中恢复。reset()方法能被调用去恢复MediaPlayer对象的空闲状态。
③非法状态异常被抛出来阻止程序错误。比如在非法的状态下,调用了prepare(),prepareAsync()或者重载的setDataSource()方法。
(3)调用 setDataSource(FileDescriptor), or setDataSource(String), or setDataSource(Context, Uri), or setDataSource(FileDescriptor, long, long), or setDataSource(MediaDataSource) 后,MediaPlayer会从空闲(Idle)状态到初始化(init)状态。
①非法状态异常抛出:在任何其它状态下被调用
②一个好的编程习惯是总是去留心在使用setDataSource()可能抛出的IllegalArgumentException和IoException。
(4)MediaPlayer对象在能被播放之前,必须信进入准备完成状态(prepared)。
①有两种方法(同步或者异步)可以使准备完成状态达到。要么调用prepare()方法return后,转换对象的状态到完成状态。要么调用prepareAsync()。prepareAsync()方法retruns后,进入到正在准备状态。然后内部的播放引擎继续做剩下的准备工作,直到准备完成。当准备完成或者prepare()方法return后,内部引擎会调用用户提供的回调方法onPrepared().前提条件是用户事先已经注册了这个接口。此时的MediaPlayer的状态是prepared。
②一个重要提示准备中状态(preparing state)是一个瞬间状态。
③IllegalStateException 被抛出,在其它的任何状态被调用。
④在准备完成状态,一些属性比如音频音量,循环等可以通过相应的方法被设置。
(5)开始播放,start()方法必须被调用。在start()方法调用之后,返回成功。MediaPlayer进入到已经播放状态(started)。isPlaying()可以用来测试MediaPlayer对象是否在已经开始状态started。
①当在已经开始状态下,内部的播放引擎会调用内部的用户提供的OnBufferingUpdateListener.onBufferingUpdate(),事先注册过监听。
这个回调方法允许应用程序跟踪流媒体的缓冲状态。
②当已在已经开始状态下,再次调用start()方法是无效的。比如想通过start()重复调用,来实现重播的功能。
(6)播放可以被暂停和停止同时当前的播放位置也可以被调整。调用pause()方法 return后,进入已停止状态paused.从已经开始状态转换到暂停状态是在播放引擎中异步发生的。反之,也是一样。也许需要花费一点时间状态被更新在调用isPlaying()。在流内容的情况下,它可能是几秒。
①调用start()去恢复一个播放暂停状态的mediaPlayer对象,同时恢复到播放位置到之前暂停的位置。当start()调用完成后,暂停状态的MediaPlayer对象重新恢复到已经开始状态的MediaPlayer对象。
②在paused状态下,调用pause()方法无效。
(7)调用stop()停止播放。同时MediaPlayer在Started,paused,prepared,playbackCompleted状态进入到stopped状态。
(8)播放的位置可以调用seekTo(int position)方法进行调整
①尽管异步的seekTo()方法能够即时的返回。实际上seek操作可能会耗费一定的时间去完成,尤其是音频视频在转化成流时。当实际的seek操作完成,内部的播放引擎会回调用户提供OnSeekComplete.onSeekComplete(),事前注册过。
②请注意,seekTo()方法也可以在其它的状态下调用,比如Prepared,Paused,PlaybackCompleted
③此外,实际播放的位置可以调用getCurrentPosition()得到。这个非常有用对音乐播放器类的应用,需要保持跟踪播放的进度。
(9)当播放达到流的结尾,播放完成。
①如果循环模式通过setLooping(true)被设置成了true.MediaPlayer将仍然保持在已经开始状态。
②如果循环模式设置成了false,播放引擎会调用用户提供的OnCompletion.onCompletion(),事先设置过。此时进入到PlayBackCompleted状态。
③播放完成状态,调用start()可以重新播放之前的视频音频资源。