MediaPlayer的功能比较强大,既可以播放音频,也可以播放视频。另外,在Android中也可以通过VideoView来播放视频,虽然VideoView比MediaPlayer简单易用,但是其定制性不如用MediaPlayer灵活。使用MediaPlayer播放音频的方法比较简单,但是要想播放视频则需要用SurfaceView实现。SurfaceView比普通的自定义View更有绘图上的优势,它可以支持全部的OpenGL ES库。
MediaPlayer可以控制音频/视频文件或流媒体的回放,可以在VideoView中找到关于如何使用这个方法的例子。使用MediaPlayer播放音频的基本步骤如下。
(1)生成MediaPlayer对象,根据播放文件从不同的地方使用不同的生成方式,具体方法可以参考MediaPlayer API。
(2)得到MediaPlayer对象后,根据实际需要调用不同的方法,例如start()、stop()、pause()和release()等。
读者需要注意的是,在不需要播放的时候要及时释放掉与MediaPlayer对象相连接的播放文件。
1.MediaPlayer的状态
图7-3显示了一个MediaPlayer对象支持的播放控制操作驱动的生命周期和状态。其中椭圆代表MediaPlayer对象可能驻留的状态,弧线表示驱动MediaPlayer在各个状态之间迁移的播放控制操作。在图中有如下两种类型的弧线。
图7-3 MediaPlayer对象
■ 由一个箭头开始的弧代表同步的方法调用。
■ 以双箭头开头的弧线代表异步方法调用。
通过图7-3可知,一个MediaPlayer对象有如下9种状态。
(1)当一个MediaPlayer对象被new操作符创建或调用了reset()方法后,它就处于Idle状态。当调用其中的release()方法后,它就处于End状态。这两种状态之间是MediaPlayer对象的生命周期。
在一个新构建的MediaPlayer对象和一个调用了reset()方法的MediaPlayer对象之间,有一个微小的但是十分重要的差别。在处于Idle状态时,调用getCurrentPosition(),getDuration(),getVideoHeight(),getVideoWidth(),setAudioStreamType(int),setLooping(boolean),setVolume(float,float),pause(),start(),stop(),seekTo(int),prepare()或者prepareAsync()方法时都会发生编程错误。当一个MediaPlayer对象刚被构建的时候,内部的播放引擎和对象的状态都没有改变。如果在这个时候调用以上方法,框架将无法回调客户端程序注册的OnErrorListener.onError()方法。但是如果这个MediaPlayer对象调用了reset()方法之后,再调用以上的那些方法,内部的播放引擎就会回调客户端程序注册的OnErrorListener.onError()方法,并传入错误的状态。
编者在此建议,一旦一个MediaPlayer对象不再被使用,应立即调用方法release()来释放在内部的播放引擎中与这个MediaPlayer对象关联的资源。资源可能包括如硬件加速组件的单态组件,如果没有调用方法release(),则可能会导致之后的MediaPlayer对象实例无法使用这种单态硬件资源,从而退回到软件实现过程继续被无限制使用甚至造成运行失败的结果。一旦MediaPlayer对象进入到End状态,则它不能再被使用,也没有办法再迁移到其他状态。
此外,使用new操作符创建的MediaPlayer对象处于Idle状态时,那些通过重载的create()方法创建的MediaPlayer对象却不是处于Idle状态。事实上,如果成功调用了重载的create()方法,那么这些对象已经是Prepare状态了。
(2)在一般情况下,由于种种原因,一些播放控制操作可能会失败,例如不支持音频/视频格式,缺少隔行扫描的音频/视频,分辨率太高,流超时等。因此,错误报告和恢复功能是非常重要的。有时因为编程错误,处于无效状态的情况下调用了一个播放控制操作可能发生。在所有这些错误条件下,内部的播放引擎会调用一个由客户端程序提供的OnErrorListener.onError()方法。客户端程序可以通过调用方法MediaPlayer.setOnErrorListener(android.media.MediaPlayer.OnErrorListener)来注册OnErrorListener。
如果一旦发生错误,MediaPlayer对象会进入到Error状态。为了重用一个处于Error状态的MediaPlayer对象,可以调用方法reset()把这个对象恢复成Idle状态。注册一个OnErrorListener来获知内部播放引擎发生错误的做法是一个好的编程习惯。在不合法的状态下调用一些方法,如方法prepare()、prepareAsync()和setDataSource()会抛出IllegalStateException异常。
(3)调用setDataSource(FileDescriptor)方法,或setDataSource(String)方法,或setData Source(Context,Uri)方法,或setDataSource(FileDescriptor,long,long)方法会使处于Idle状态的对象迁移到Initialized状态。
若当此MediaPlayer处于其他的状态下,调用setDataSource()方法,会抛出IllegalStateException异常。好的编程习惯是不要疏忽了调用setDataSource()方法可能会抛出的IllegalArgumentException异常和IOException异常。
(4)在开始播放之前,MediaPlayer对象必须进入Prepared状态。在此有如下两种方法(同步和异步)可以使MediaPlayer对象进入Prepared状态。
■ 调用prepare()方法(同步):此方法返回就表示该MediaPlayer对象已经进入了Prepared
状态。
■ 调用prepareAsync()方法(异步):此方法会使此MediaPlayer对象进入Preparing状态
并返回,而内部的播放引擎会继续未完成的准备工作。
当同步版本返回时或异步版本的准备工作完全完成时,会调用客户端程序员提供的监听方法OnPreparedListener.onPrepared()。可以调用方法MediaPlayer.setOnPreparedListener(android. media.MediaPlayer.OnPreparedListener)来注册OnPreparedListener。
Preparing是一个中间状态,在此状态下调用任何具备影响的方法的结果都是未知的。在不合适的状态下调用prepare()和prepareAsync()方法会抛出IllegalStateException异常。当MediaPlayer对象处于Prepared状态时,可以调整音频/视频的属性,如音量、播放时是否一直亮屏、循环播放等。
(5)在要开始播放时必须调用start()方法。当此方法成功返回时,MediaPlayer的对象处于Started状态。isPlaying()方法可以被调用,来测试某个MediaPlayer对象是否在Started状态
当处于Started状态时,内部播放引擎会调用客户端程序员提供的OnBufferingUpdate Listener.onBufferingUpdate()回调方法,此回调方法允许应用程序追踪流播放的缓冲状态。对一个已经处于Started状态的MediaPlayer对象调用start()方法没有影响。
(6)播放可以被暂停、停止以及调整当前播放位置。当调用pause()方法并返回时,会使MediaPlayer对象进入Paused状态。注意Started与Paused状态的相互转换在内部的播放引擎中是异步的。所以可能需要一点时间在isPlaying()方法中更新状态,若在播放流内容,则这段时间可能会有几秒钟。
调用start()方法会让一个处于Paused状态的MediaPlayer对象从之前暂停的地方恢复播放。当调用start()方法返回的时候,MediaPlayer对象的状态会又变成Started状态。对一个已经处于Paused状态的MediaPlayer对象,pause()方法没有影响。
(7)调用stop()方法会停止播放,并且还会让一个处于Started、Paused、Prepared或PlaybackCompleted状态的MediaPlayer进入Stopped状态。对一个已经处于Stopped状态的MediaPlayer对象,stop()方法没有影响。
(8)调用seekTo()方法可以调整播放的位置。方法seekTo(int)是异步执行的,所以它可以马上返回,但是实际的定位播放操作可能需要一段时间才能完成,尤其是播放流形式的音频/视频。当实际的定位播放操作完成之后,内部的播放引擎会调用客户端程序员提供的OnSeekComplete.onSeekComplete()回调方法。可以通过setOnSeekCompleteListener(OnSeek CompleteListener)方法注册。
我们在此需要注意,seekTo(int)方法也可以在其他状态下调用,比如Prepared、Paused和PlaybackCompleted状态。此外,可以调用getCurrentPosition()方法得到目前的播放位置,它可以帮助,例如音乐播放器应用程序不断更新播放进度。
(9)当播放到流的末尾时完成播放。如果调用了setLooping(boolean)方法开启了循环模式那么这个MediaPlayer对象会重新进入Started状态。如果没有开启循环模式,那么内部的播放引擎会调用客户端程序员提供的OnCompletion.onCompletion()回调方法。可以通过调用方法MediaPlayer.setOnCompletionListener(OnCompletionListener)来设置。内部的播放引擎一旦调用了OnCompletion.onCompletion()回调方法,说明这个MediaPlayer对象进入了Playback Completed状态。当处于PlaybackCompleted状态的时候,可以再调用start()方法来让这个MediaPlayer对象再进入Started状态。
2.MediaPlayer方法的有效状态和无效状态
■ getCurrentPosition{Idle,Initialized,Prepared,Started,Paused,Stopped,PlaybackCompleted} {Error}:有效状态成功呼叫该方法不会改变此时的状态,无效的状态呼叫该方法则会使该状态转换到错误状态中。
■ getDuration{Prepared,Started,Paused,Stopped,PlaybackCompleted}{Idle,Initialized, Error}:有效状态成功呼叫该方法不会改变此时的状态,无效的状态呼叫该方法则会使该状态转换到错误状态中。
■ getVideoHeight{Idle,Initialized,Prepared,Started,Paused,Stopped,PlaybackCompleted}{Error}:有效状态成功呼叫该方法不会改变此时的状态,无效的状态呼叫该方法则会使该状态转换到错误状态中。
■ getVideoWidth{Idle,Initialized,Prepared,Started,Paused,Stopped,PlaybackCompleted}{Error}:有效状态成功呼叫该方法不会改变此时的状态,无效的状态呼叫该方法则会使该状态转换到错误状态中。
■ isPlaying{Idle,Initialized,Prepared,Started,Paused,Stopped,PlaybackCompleted}{Error}:有效状态成功呼叫该方法不会改变此时的状态,无效的状态呼叫该方法则会使该状态转换到错误状态中。
■ pause{Started,Paused}{Idle,Initialized,Prepared,Stopped,PlaybackCompleted,Error}:有效状态成功呼叫该方法则改变此时的状态到暂停状态,无效的状态呼叫该方法则会使该状态转换到错误状态中。
■ prepare{Initialized,Stopped}{Idle,Prepared,Started,Paused,PlaybackCompleted, Error}:有效状态成功呼叫该方法则改变此时的状态到准备状态,无效的状态呼叫该方法则会抛出错误状态异常。
■ prepareAsync{Initialized,Stopped}{Idle,Prepared,Started,Paused,PlaybackCompleted, Error}:有效状态成功呼叫该方法则改变此时的状态到准备状态,无效的状态呼叫该方法则会抛出错误状态异常。
■ release any{}:在release()中对象不再是可用的。
■ reset{Idle,Initialized,Prepared,Started,Paused,Stopped,PlaybackCompleted,Error}{}:在reset()后,对象如刚创建的一样。
■ seekTo{Prepared,Started,Paused,PlaybackCompleted}{Idle,Initialized,Stopped, Error}:有效状态成功呼叫该方法则改变此时的状态到暂停状态,无效的状态呼叫该方法则会使该状态转换到错误状态中。
■ setAudioStreamType{Idle,Initialized,Stopped,Prepared,Started,Paused, PlaybackCompleted}{Error}:有效状态成功呼叫该方法则改变此时的状态到暂停状态
■ setDataSource{Idle}{Initialized,Prepared,Started,Paused,Stopped,PlaybackCompleted, Error}:有效状态成功呼叫该方法则改变此时的状态到初始化状态,无效的状态呼叫该方法则会抛出错误状态异常。
■ setDisplay any{}:任何状态都可以呼叫该方法且不会改变当前对象的状态。
■ setLooping{Idle,Initialized,Stopped,Prepared,Started,Paused,PlaybackCompleted}{Error}:有效状态成功呼叫该方法不会改变此时的状态,无效的状态呼叫该方法则会使该状态转换到错误状态中。
■ isLooping any{}:任何状态都可以呼叫该方法且不会改变当前对象的状态。
■ setOnBufferingUpdateListener any{}:任何状态都可以呼叫该方法且不会改变当前对象的状态。
■ setOnCompletionListener any{}:任何状态都可以呼叫该方法且不会改变当前对象的状态。
■ setOnErrorListener any{}:任何状态都可以呼叫该方法且不会改变当前对象的状态。
■ setOnPreparedListener any{}:任何状态都可以呼叫该方法且不会改变当前对象的状态。
■ setOnSeekCompleteListener any{}:任何状态都可以呼叫该方法且不会改变当前对象的状态。
■ setScreenOnWhilePlaying any{}:任何状态都可以呼叫该方法且不会改变当前对象的状态。(www.xing528.com)
■ setVolume{Idle,Initialized,Stopped,Prepared,Started,Paused,PlaybackCompleted}{Error}:成功调用该方法不会改变当前的状态。
■ setWakeMode any{}:任何状态都可以呼叫该方法且不会改变当前对象的状态。
■ start{Prepared,Started,Paused,PlaybackCompleted}{Idle,Initialized,Stopped,Error}:有效状态成功呼叫该方法则改变此时的状态到开始状态,无效的状态呼叫该方法则会转换到错误状态。
■ stop{Prepared,Started,Stopped,Paused,PlaybackCompleted}{Idle,Initialized,Error}:有效状态成功呼叫该方法则改变此时的状态到停止状态,无效的状态呼叫该方法则会转换到错误状态。
3.MediaPlayer方法的接口
■ 接口MediaPlayer.OnBufferingUpdateListener:唤起指明的网络上的媒体资源以缓冲流的形式播放。
■ 接口MediaPlayer.OnCompletionListener:为当媒体资源播放完成后唤起的回放而定义
■ 接口MediaPlayer.OnErrorListener:定义了当在异步操作的时候(其他错误将会在呼叫方法的时候抛出异常)出现错误后唤起的回放操作。
■ 接口MediaPlayer.OnInfoListener:定义了与一些关于媒体、播放的信息以及相关警告被唤起的回放。
■ 接口MediaPlayer.OnPreparedListener:定义了为播放媒体资源而唤起回放的准备。
■ 接口MediaPlayer.OnSeekCompleteListener:定义了指明查找操作完成后唤起的回放操作。
■ 接口MediaPlayer.OnVideoSizeChangedListener:定义了当视频大小被首次知晓或更新时而唤起的回放。
4.MediaPlayer方法的常量
■ int MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK:视频流及其容器不支持连续的处于非播放文件内的播放视频序列。
■ int MEDIA_ERROR_SERVER_DIED:媒体服务终止。
■ int MEDIA_ERROR_UNKNOWN:未指明的媒体播放错误。
■ int MEDIA_INFO_BAD_INTERLEAVING:表示不正确的交叉存储技术,意味着媒体被不适当地交叉存储或者根本就没有交叉存储。
■ int MEDIA_INFO_METADATA_UPDATE:一套新的可用的元数据。
■ int MEDIA_INFO_NOT_SEEKABLE:媒体位置不可查找。
■ int MEDIA_INFO_UNKNOWN:未指明的媒体播放信息。
■ int MEDIA_INFO_VIDEO_TRACK_LAGGING:视频对于解码器太复杂以至于不能以足够快的帧率进行解码。
5.MediaPlayer方法的公共方法
■ static MediaPlayer create(Context context,Uri uri):根据给定的uri方便地创建MediaPlayer对象的方法。
■ static MediaPlayer create(Context context,int resid):根据给定的资源id方便地创建MediaPlayer对象的方法。
■ static MediaPlayer create(Context context,Uri uri,SurfaceHolder holder):根据给定的uri方便地创建MediaPlayer对象的方法。
■ int getCurrentPosition():获得当前播放的位置。
■ int getDuration():获得文件段。
■ int getVideoHeight():获得视频的高度。
■ int getVideoWidth():获得视频的宽度。
■ boolean isLooping():检查MediaPlayer是否处于循环状态。
■ boolean isPlaying():检查MediaPlayer是否在播放。
■ void pause():暂停播放。
■ void prepare():让播放器处于准备状态(同步的)。
■ void prepareAsync():让播放器处于准备状态(异步的)。
■ void release():释放与MediaPlayer相关的资源。
■ void reset():重置MediaPlayer到初始化状态。
■ void seekTo(int msec):搜寻指定的时间位置。
■ void setAudioStreamType(int streamtype):为MediaPlayer设定音频流类型。
■ void setDataSource(String path):设定使用的数据源、文件路径或http/rtsp地址。
■ void setDataSource(FileDescriptor fd,long offset,long length):设定使用的数据源(filedescriptor)。
■ void setDataSource(FileDescriptor fd):设定使用的数据源(filedescriptor)。
■ void setDataSource(Context context,Uri uri):设定一个如Uri内容的数据源。
■ void setDisplay(SurfaceHolder sh):设定播放该Video的媒体播放器的SurfaceHolder。
■ void setLooping(boolean looping):设定为循环或不循环播放。
■ void setOnBufferingUpdateListener(MediaPlayer.OnBufferingUpdateListener listener):注册一个当网络缓冲数据流变化的时候唤起的播放事件。
■ void setOnCompletionListener(MediaPlayer.OnCompletionListener listener):注册一个当媒体资源在播放的时候到达终点时唤起的播放事件。
■ void setOnErrorListener(MediaPlayer.OnErrorListener listener):注册一个当在异步操作过程中发生错误的时候唤起的播放事件。
■ void setOnInfoListener(MediaPlayer.OnInfoListener listener):注册一个当有信息/警告出现的时候唤起的播放事件。
■ void setOnPreparedListener(MediaPlayer.OnPreparedListener listener):注册一个当媒体资源准备播放时候唤起的播放事件。
■ void setOnSeekCompleteListener(MediaPlayer.OnSeekCompleteListener listener):注册一个当搜寻操作完成后唤起的播放事件。
■ void setOnVideoSizeChangedListener(MediaPlayer.OnVideoSizeChangedListener listener):注册一个当视频大小知晓或更新后唤起的播放事件。
■ void setScreenOnWhilePlaying(boolean screenOn):控制当视频播放发生时是否使用SurfaceHolder来保持屏幕。
■ void setVolume(float leftVolume,float rightVolume):设置播放器的音量。
■ void setWakeMode(Context context,int mode):为MediaPlayer设置低等级的电源管理状态。
■ void start():开始或恢复播放。
■ void stop():停止播放。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。