解读官方Android MediaPlayer API(1)

时间:2024-03-13 16:41:37
public class MediaPlayer

extends Object

MediaPlayer class 能够用来使用来控制vudio/video(音频或视频)文件和流文件的播放.举个例子可以在

VideoView 中了解怎么样使用这些方法。请看Audio and Video 中附加的文档。

MedioPlayer状态图如下:

audio/video(音频/视频)文件和流的控制是通过状态机制管理的。以下图标显示了 MediaPlayer 对象在播

放控制操作支持下被执行的生命周期和状态。椭圆代表MedioPlayer对象可能驻留的状态。弧线代表播放控制

操作驱使对象的状态间的转换。这里有两种弧线类型。单箭头的弧线代表同步的方法调用,而双箭头的弧线代

表异步的方法调用。

解读官方Android MediaPlayer API(1)

从状态图,我们可以知道MedioPlayer对象有以下的状态:

1 ) 当使用new或调用reset()后MedioPlayer对象就会被创建,对象将处在Idle状态;并且当release()被调用后,

对象将处于End状态。 这两种状态之间是MedioPlayer对象的生命周期。

1.1) 这里有点微妙但又很重要的不同是在MedioPlayer对象的创建和创建并调用reset()之后的MedioPlayer对象中

在Idle状态时调用例如getCurrentPosition()getDuration()getVideoHeight()getVideoWidth(),

setAudioStreamType(int) setLooping(boolean)setVolume(float, float)pause()start()stop(),seekTo(int)

prepare() or prepareAsync() 这些方法,都编程的错误。在MediaPlayer对象被构建后如果这些方法被调用,框架将无法被

内部的播放引擎回调OnErrorListener.onError() 并且对象的状态不会改变。但如果MediaPlayer对象调用了reset()之后,调

用这些方法,内部的播放引擎将能够回调 OnErrorListener.onError()方法,并且对象会转入Error状态。

1.2)并且推荐一旦MediaPlayer不再使用,就立即调用release()方法那么内部播放引擎对这个MediaPlayer对象的关联将会立即释放资源。

资源包括单一的资源例如计算机加速硬件组件(可理解为只能够一个对象使用的资源),所以若没有调用release()方法可能会导致后面

的MediaPlayer对象无法使用这单一资源 从而退回到软件实现或运行失败,一旦MediaPlayer对象进入了End状态,它将不再被使

用,并且没有办法回到其他任何状态。

1.3)此外,使用new创建的MediaPlayer对象将处于Idle状态,然而那些通过重载的create()便利方法创建的MediaPlayer对象却不是出在Idle状态。

实际上,如果成功调用create()方法,那么这些对象将是处在Prepared状态。

2)通常,一些播放控制操作由于各种各样的原因而运行失败,例如 audio/video的格式不支持;缺少隔行扫描的audio/video;分表率太高;流超时等此类原因。

那么,错误的报告和恢复在这些情况下是重要的。有时,由于程序设计的错误,在一个无效的状态下调用一个播放控制操作也可能发生。在所有这些错误条件下,

内部的播放引擎会调用一个由客户端程序员提供的OnErrorListener.onError()方法。客户端程序员可以通过调用Medialayer.setOnErrorListener(android.media.

MediaPlayer.OnErrorListener)方法来注册OnErrorListener.

2.1)一旦错误发生,值得注意的是,MediaPlayer对象会进入Error状态,即使没有注册OnErrorListener,应用还是会进入Error状态。

2.2)为了重新使用在Error状态的MediaPlayer对象使它从Error状态恢复,那么reset()方法的调用能够恢复对象到Idle状态。

2.3)一个好的程序设计实践你的应用,是有注册一个OnErrorListener用来注意来自内部播放引擎的Error的通知。

2.4)在一个invalid状态下, 例如调用prepare(),   prepareAsync(),或者一个重写的setDataSource方法。IlleglStateException异常被抛出,可以防止程序设计的错误.。

3)调用setDataSource(FileDescriptor)方法,或setDataSource(String)方法,或setDataSource(Context,Uri)方法,

或setDataSource(FileDescriptor,long,long)方法会使处于Idle状态的对象迁移到Initialized状态。

3.1)若当对象在任何一个其他状态下调用setDataSource()会抛出 IllegalStateException 异常。

3.2)好的编程习惯是不要疏忽了调用setDataSource()方法的时候可能会抛出的IllegalArgumentException异常和IOException异常。 

4)一个MedioPlayer对象在播放开始之前必须首先进入Prepared状态。

4.1)有两种方法(同步和异步)可以使MediaPlayer对象进入Prepared状态:要么调用prepare()方法(同步),

此方法返回就表示该MediaPlayer对象已经进入了Prepared状态;要么调用prepareAsync()方法(异步),此方法会使此

MediaPlayer对象进入Preparing状态并返回,而内部的播放引擎会继续未完成的准备工作。当同步版本返回时或异步版本

的准备工作完全完成时就会调用客户端程序员提供的OnPreparedListener.onPrepared()监听方法。可以调MediaPlayer

.setOnPreparedListener(android.media.MediaPlayer.OnPreparedListener)方法来注册OnPreparedListener.

4.2)值得注意的是Preparing是个短暂的状态,在此状态下调用任何具备边影响的方法的结果都是未知的!

4.3)在任何其他状态下,调用prepare()和prepareAsync()方法会抛出IllegalStateException异常。

4.4)当MediaPlayer对象处于Prepared状态的时候,可以调用相应的方法调整音频/视频的属性,如音量,

播放时是否一直亮屏,循环播放等。 

5)想要开始播放,start()必须需要调用。在start()成功的调用之后MediaPlayer 对象将进入 Started的状态,isPlaying()方法可

以被调用来测试某个MediaPlayer对象是否在Started状态。

5.1)当在 Started状态,内部播放引擎会调用客户端程序员提供的OnBufferingUpdateListener.onBufferingUpdate()回调方法,

通过setOnBufferingUpdateListener(OnBufferingUpdateListener)注册监听。此回调方法允许应用程序追踪流播放的缓冲的状态。

5.2)对一个已经处于Started 状态的MediaPlayer对象调用start()方法没有影响。

6)播放可以被暂停,停止,和调整当前的播放位置。当调用pause()方法并返回时,会使MediaPlayer对象进入Paused状态。

注意Started与Paused状态的相互转换在内部的播放引擎中是异步的。所以可能需要一点时间在isPlaying()方法中更新

状态,若在播放流内容,这段时间可能会有几秒钟。

6.1) 调用start()方法会让一个处于Paused状态的MediaPlayer对象从之前暂停的地方恢复播放。当调用start()方法

返回的时候,MediaPlayer对象的状态会又变成Started状态。


6.2) 对一个已经处于Paused状态的MediaPlayer对象pause()方法没有影响。

7) 调用stop()方法会停止播放,并且还会让一个处于Started,Paused,Prepared或PlaybackCompleted状态的MediaPlayer进入Stopped状态。

7.1)一旦MediaPlayer在Stopped状态,mediaPlayer不能开始播放,直到prepare() or prepareAsync()调用后,

使MediaPlayer再次进入Prepared状态之后。

7.2)对一个已经处于Stopped状态的MediaPlayer对象stop()方法没有影响。

8) 调用seekTo()方法可以调整播放的位置。

8.1)seekTo(int)方法是异步执行的,所以它可以马上返回,但是实际的定位播放操作可能需要一段时间才能完成,

尤其是播放流形式的音频/视频。当实际的定位播放操作完成之后,内部的播放引擎会调用客户端程序员提供的

OnSeekComplete.onSeekComplete()回调方法。可以通过setOnSeekCompleteListener(OnSeekCompleteListener)方法注册。

8.2)注意,seekTo(int)方法也可以在其它状态下调用,比如Prepared,Paused和PlaybackCompleted状态。

8.3)此外,目前的播放位置,实际可以调用getCurrentPosition()方法得到,它可以帮助如音乐播放器的应用程序不断更新播放进度

9) 当播放到流的末尾,播放就完成了。

9.1) 如果调用了setLooping(boolean)方法开启了循环模式,那么这个MediaPlayer对象会重新进入Started状态。



9.2) 若没有开启循环模式,那么内部的播放引擎会调用客户端程序员提供的OnCompletion.onCompletion()回调方法。

可以通过调用MediaPlayer.setOnCompletionListener(OnCompletionListener)方法来设置。内部的播放引擎一旦调

用了OnCompletion.onCompletion()回调方法,说明这个MediaPlayer对象进入了PlaybackCompleted状态。

9.3) 当处于PlaybackCompleted状态的时候,可以再调用start()方法来让这个MediaPlayer对象再进入Started状态。 

参考文献:

1.谷歌官方Android SDK开发文档

2.http://my.oschina.net/zhangqingcai/blog/29660