且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Android音视频——系统播放器介绍(二)

更新时间:2022-06-18 03:10:41

在上文Android音视频——系统播放器介绍(一)中,介绍到了状态,但是没有详细讲解,本篇就为大家带来MediaPlayer状态涉及到的方法。
Android音视频——系统播放器介绍(二)
此图是官方图例
椭圆代表MediaPlayer可能停留的状态。椭圆之间的箭头表示方法调用,状态切换的方向。单箭头表示方法同步调用,双箭头表示异步调用。

从图中我们可以看出MediaPlayer的状态切换和涉及到的方法。

Idle-End

当new一个MediaPlayer或者调用了reset函数,当前MediaPlayer会处于Idle状态。调用release后,会处于End状态。在这2个状态之间的可以看做是MediaPlayer的生命周期。

Error

一些情形可能会让MediaPlayer操作失败,比如不支持的音视频格式,分辨率过高,网络超时等等。
因此在这些情形下错误处理和恢复非常重要。有时候编程错误也会导致MediaPlayer操作错误。
开发者可以设置错误监听器setOnErrorListener(android.media.MediaPlayer.OnErrorListener)。当错误发生时,会调用用户实现的OnErrorListener.onError()方法。

不管有没有设置监听器,错误发生时MediaPlayer会进入Error状态。

为了重复使用同一个MediaPlayer对象,可以使用reset()方法把它从Error状态恢复到Idle状态。
设置错误监听器OnErrorListener是一个好的编程习惯。开发者可以监听到播放引擎的错误通知。
有时候会抛出IllegalStateException异常,比如在错误的状态调用了prepare(), prepareAsync()方法,或是setDataSource方法。

Initialized

当调用 seDataSource(FileDescriptor)setDataSource(String)、setDataSource(Context,Ur)、 seiDataSource(FileDescriptor,long,long)其中一个函数时,将传递 MediaPlayer 的 Idle 状态变成 nitialized(初始化状态,如果 setDatSource 在非 ldle 状态时调用,会抛出 legaStateException异常。当重载 setDataSource 时,需要抛出 llegalArgumentException 和 1OException 这两个异常。

Prepared

MediaPlayer有两种途径到达 Prepared 状态,一种是同步方式,另一种是异步方式。同步方式主要使用本地音视频文件,异步方式主要使用网络数据,需要缓冲数据。调用 prepare(同步函数)将传递 MediaPlayer 的 Initialized 状态变成 Prepared 状态,或者调用 prepareAsync(异步函数)将传递 MediaPlayer 的 Initialized 状态变成 Preparing 状态,最后到 Prepared 状态。如果应用层事先注册过 setOnPreparedListener.播放器内部将回调用户设置的 OnPreparedListener 中的 onPrepared 回调函数,注意,Preparing 是一个瞬间状态(可理解为时间比较短)。

Started

在 MediaPlayer 进入 Prepared 状态后,上层应用即可设置一些属性,如音视频的音量。 screenOnWhilePlaying、looping 等。在播放控制开始之前,必须调用 start 涵数并成功返回。 Mediaplayer的状态开始由 Preparod 状态变成 Started 状态。当处于 Started 状态时,如果用户先注册过setOnBufferingUpdateListener,播放器内部会开始回调 OnBuferingUpdatel itene.o BufferingUpdate,这个回调函数主要使应用程序保持跟踪音视频流的 buffering(缓冲) status,如果 MediaPlayer 已经处于 Started 状态,再调用 start 函数是没有任何作用的。

Paused

MediaPlayer 在播放控制时可以是 Paused(暂停)和 Stopped(停止)状态的,且当前的播放时进度可以被调整,当调用 MediaPlayerpause 函数时,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 状态。
在Seck 操作完成后,如果事先在 MediaPlayer 注册了 sctOnScckCompleteListener,播放器内部将回调 OnSeckComplete.onSeekComplete 函数。当然 seckTo 函数也可以在其他状态下被让用,如 Prepared、Paused 及 PlaybackCompleted 状态。

PlaybackCompleted

当前播放的位置可以通过getCurrentPosition 函数获取,通过 getCurrentPosition 函数,可跟踪播放器的播放进度。
当 MediaPlayer 播放到数据流的末尾时,一次播放过程完成。在 MediaPlayer 中事先调 setLooping(boolean)并设置为true,表示循环播放,MediaPlayer 依然处于 Started 状态。如果用 setLooping(boolean)并设置为 false(表示不循环播放),并且事先在 MediaPlayer 上注册过 setOnCompletionListener,播放器内部将回调OnCompletion.onCompletion 函数,这就表明 MediaPlayer开始进入 PlaybackCompleted(播放完成)状态。当处于 PlaybackCompleted 状态时,调用start函数,将重启播放器从头开始播放数据。