MediaPlayer基础-生命周期状态分析

Posted hymKing

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MediaPlayer基础-生命周期状态分析相关的知识,希望对你有一定的参考价值。

注:本文参照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()可以重新播放之前的视频音频资源。

以上是关于MediaPlayer基础-生命周期状态分析的主要内容,如果未能解决你的问题,请参考以下文章

播放器MediaPlayer解读

markdown Android MediaPlayer的生命周期

[React 基础系列] 状态 & 状态更新 & 生命周期方法

Java并发基础Java线程的生命周期

Android零基础入门第75节:Activity状态和生命周期方法

Flutter 中的生命周期分析