播放器之MediaPlayer详解与总结

达芬奇密码2018-07-23 09:31

一、MediaPlayer详解

二、常用方法

1、使用进度条:

2prepare方法和prepareAsync方法的区别

3、与MediaPlayer有关的事件监听器:

4MediaplayeronCompletion的异常调用问题解决

三、 可优化方向

 

一、MediaPlayer详解:

Audioplayer sdk播放器 1.0版本使用的是Android系统音频/ 视频 MediaPlayer类。MediaPlayer类公共方法 蓝色(重要方法)

1static MediaPlayer  create(Context context, Uri uri, SurfaceHolder holder)

指定从资源ID对应的资源文件中来装载音乐文件,同时指定了SurfaceHolder对象并返回MediaPlyaer对象。

2static MediaPlayer     create(Context context, int resid) 指定从资源ID对应的资源文件中来装载音乐文件,并返回新创建的MediaPlyaer对象。

3static MediaPlayer     create(Context context, Uri uri) 从指定Uri装在音频文件,并返回新创建的MediaPlayer对象。

4int   getCurrentPosition() 获取当前播放的位置。

5int   getDuration() 获取音频的时长。

6int   getVideoHeight() 获取视频的高度。

7int   getVideoWidth() 获取视频的宽度。

8boolean isLooping() 判断MediaPlayer是否正在循环播放。

9boolean isPlaying() 判断MediaPlayer是否正在播放。

10void pause() 暂停播放。

11void prepare()准备播放(装载音频),调用此方法会使MediaPlayer进入Prepared状态。

12void prepareAsync()准备播放异步音频。

13void release() 释放媒体资源。

14void     reset() 重置MediaPlayer进入未初始化状态。

15void     seekTo(int msec) 寻找指定的时间位置。

16void     setAudioStreamType(int streamtype) 设置音频流的类型。

17void     setDataSource(String path) 指定装载path路径所代表的文件。

18void   setDataSource(Context context, Uri uri, Map<String, String headers)

指定装载uri所代表的文件。

19void     setDataSource(Context context, Uri uri) 指定装载uri所代表的文件。

20void     setDataSource(FileDescriptor fd, long offset, long length) 指定装载fd所代表的文件中从offset开始长度为length的文件内容。

21void     setDataSource(FileDescriptor fd) 指定装载fd所代表的文件。

22void     setDisplay(SurfaceHolder sh) 设置显示方式。

23void     setLooping(boolean looping)设置是否循环播放。

24void     setNextMediaPlayer(MediaPlayer next) 设置当前流媒体播放完毕,下一个播放的MediaPlayer

25 void setOnBufferingUpdateListener(MediaPlayer.OnBufferingUpdateListener listener)注册一个回调函数,在网络视频流缓冲变化时调用。

26void     setOnCompletionListener(MediaPlayer.OnCompletionListener listener) Media Player的播放完成事件绑定事件监听器。

27void     setOnErrorListener(MediaPlayer.OnErrorListener listener)

MediaPlayer的播放错误事件绑定事件监听器。

28void     setOnPreparedListener(MediaPlayer.OnPreparedListener listener)

MediaPlayer调用prepare()方法时触发该监听器。

29void     setOnSeekCompleteListener(MediaPlayer.OnSeekCompleteListener listener)MediaPlayer调用seek()方法时触发该监听器。

30setOnVideoSizeChangedListener(MediaPlayer.OnVideoSizeChangedListener listener)注册一个用于监听视频大小改变的监听器。

31void setScreenOnWhilePlaying(boolean screenOn)置是否使用SurfaceHolder来显示。

32void setSurface(Surface surface)设置Surface

33void setVideoScalingMode(int mode) 设置视频缩放的模式。

34void setVolume(float leftVolume, float rightVolume) 设置播放器的音量。

35void setWakeMode(Context context, int mode) MediaPlayer设置低级电源管理行为。.

36void start() 开始或恢复播放。

37void stop() 停止播放

二、常用方法

1、使用进度条:

    歌单中每一首歌曲开始播放前,都会回调此接口,进度条用SeekBar实现,同时用户也可以利用SeekBar的滑块来控制音乐的播放。

SeekBar需要使用的一些方法:

1setProgressint value):设置滑块的位置方法为。

2setMax(int value):设置进度条的最大长度。

3setOnSeekBarChangeListener(OnSeekBarChangeListener l):设置SeekBar的进度改变事件。

MusicPlayer需要使用的一些方法:

1getDuration():获得音乐长度为。

2getCurrentPosition():获得现在播放的位置。

3seekTo(int msec):调用seekTo()方法可以调整播放的位置。( seekTo(int)方法是异步执行的,所以它可以马上返回,但是实际的定位播放操作可能需要一段时间才能完成,尤其是播放流形式的音频/视频。当实际的定位播放操作完成之后,内部的播放引擎会调用客户端程序员提供的OnSeekComplete.onSeekComplete()回调方法。可以通过setOnSeekCompleteListener(OnSeekCompleteListener)方法注册。seekTo(int)方法也可以在其它状态下调用,比如PreparedPausedPlaybackCompleted状态。此外,目前的播放位置,实际可以调用getCurrentPosition()方法得到,它可以帮助如音乐播放器的应用程序不断更新播放进度。)



用户手动拖动进度条。

 

 

2prepare方法和prepareAsync方法的区别

   prepare方法是将资源同步缓存到内存中,一般加载本地较小的资源可以用这个,如果是较大的资源或者网络资源建议使用prepareAsync方法,异步加载。但如果想让资源启动,即start()起来,因为在异步中,如果不设置监听直接start的话,是拿不到这个资源,如果让线程睡眠一段时间,则可以取得资源,因为这个时候,异步线程已经取得资源,但不可能使用线程睡眠的方式来获取资源,所以就需要设置监听事件setOnPreparedListener();来通知MediaPlayer资源已经获取到了,然后实现onPrepared(MediaPlayer mp)方法.在里面启动MediaPlayer



 

3、与MediaPlayer有关的事件监听器:

MediaPlayer提供了一些绑定事件监听器的方法,用于监听MediaPlayer播放过程中所发生的特定事件,绑定事件监听器的方法如下。

26void     setOnCompletionListener(MediaPlayer.OnCompletionListener listener) Media Player的播放完成事件绑定事件监听器。

27void     setOnErrorListener(MediaPlayer.OnErrorListener listener)

MediaPlayer的播放错误事件绑定事件监听器。

28void     setOnPreparedListener(MediaPlayer.OnPreparedListener listener)

MediaPlayer调用prepare()方法时触发该监听器。

29void     setOnSeekCompleteListener(MediaPlayer.OnSeekCompleteListener listener)MediaPlayer调用seek()方法时触发该监听器。

因此可以在创建一个MediaPlayer对象之后,通过为该MediaPlayer绑定监听器来监听相应的事件



 

4MediaplayeronCompletion的异常调用问题解决

    onCompletion()正常情况下是在一首歌曲播放完之后会得到调用,但是现在发现有时候会异常调用,找了一些资料,发现如果在mediaplayer setDataSource之前就调用了类似 getDuration()的方法就会出错,onCompletion()就会被调用。(例如: 通过新开一个线程,不断地通过getDuration()来获取歌曲进度的,但是当我们快速点击list上面的歌曲的时候,歌曲在切换的瞬间(即当mediaplayer reset之后,setDataSource之前),那个线程来不及反应还没停止继续在getDuration(),所以会有很大的几率出现onCompletion()被异常调用的情况。)

解决方法是:onCompletion()里面进行判断,如果当前状态是播放或者暂停情况下,onCompletion()被调用,就不更View!  因为在点击list上的歌曲之前只有2种可能性,要么播放started,要么paused,其他状态点击list上的歌曲不会出现异常调用onCompletion()的可能,而我们正常情况下一首歌播放完切换下一首歌的时候mediaplayer的状态不会是started或者paused, 那么现在问题又来了,怎么获取当前mediaplayer状态,mediaplayer本身是没有这个方法的,只有isPlaying判断是否在播放,对于我们呢没有用,所以我们自己需要加一个状态码,在每次mediaplayer状态切换的时候对这个状态码进行修改。



三、可优化方向:

1、 由于时间很紧张,version1.0版本没有进行多线程的管理,后续可进行优化。

2、可以把回调接口进行分类,相近相似的放到一起。

 

附上mediaplayer生命周期图:

1End状态:通过release()方法可以进入End状态,只要MediaPlayer对象不再被使用,就应当尽快将其通过release()方法释放掉,以释放相关的软硬件组件资源,这其中有些资源是只有一份的(相当于临界资源)。如果MediaPlayer对象进入了End状态,则不会再进入任何其他状态了。

2Initialized状态:这个状态比较简单,MediaPlayer调用setDataSource()方法就进入Initialized状态,表示此时要播放的文件已经设置好了。

提示:若当此MediaPlayer处于其它的状态下,调用setDataSource()方法,会抛出IllegalStateException异常。

3Prepared状态:初始化完成之后还需要通过调用prepare()prepareAsync()方法,这两个方法一个是同步的一个是异步的,只有进入Prepared状态,才表明MediaPlayer到目前为止都没有错误,可以进行文件播放。

提示:在不合适的状态下调用prepare()prepareAsync()方法会抛出IllegalStateException异常。当MediaPlayer对象处于Prepared状态的时候,可以调整音频/视频的属性,如音量,播放时是否一直亮屏,循环播放等。

4Preparing状态:这个状态比较好理解,主要是和prepareAsync()配合,如果异步准备完成,会触发OnPreparedListener.onPrepared(),进而进入Prepared状态。

5Started状态:显然,MediaPlayer一旦准备好,就可以调用start()方法,这样MediaPlayer就处于Started状态,这表明MediaPlayer正在播放文件过程中。可以使用isPlaying()测试MediaPlayer是否处于了Started状态。如果播放完毕,而又设置了循环播放,则MediaPlayer仍然会处于Started状态,类似的,如果在该状态下MediaPlayer调用了seekTo()或者start()方法均可以让MediaPlayer停留在Started状态。

6Paused状态:Started状态下MediaPlayer调用pause()方法可以暂停MediaPlayer,从而进入Paused状态,MediaPlayer暂停后再次调用start()则可以继续MediaPlayer的播放,转到Started状态,暂停状态时可以调用seekTo()方法,这是不会改变状态的。

7Stop状态:Started或者Paused状态下均可调用stop()停止MediaPlayer,而处于Stop状态的MediaPlayer要想重新播放,需要通过prepareAsync()prepare()回到先前的Prepared状态重新开始才可以。

8PlaybackCompleted状态:文件正常播放完毕,而又没有设置循环播放的话就进入该状态,并会触发OnCompletionListeneronCompletion()方法。此时可以调用start()方法重新从头播放文件,也可以stop()停止MediaPlayer,或者也可以seekTo()来重新定位播放位置。

9Error状态:在一般情况下,由于种种原因一些播放控制操作可能会失败,如不支持的音频/视频格式,缺少隔行扫描的音频/视频,分辨率太高,流超时等原因,等等会触发会触发OnErrorListener.onError()事件,此时MediaPlayer会进入Error状态,及时捕捉并妥善处理这些错误是很重要的,可以帮助我们及时释放相关的软硬件资源,也可以改善用户体验。

开发者可以通过setOnErrorListener(android.media.MediaPlayer.OnErrorListener设置监听器来监听MediaPlayer是否进入Error状态。如果MediaPlayer进入了Error状态,可以通过调用reset()来恢复,使得MediaPlayer重新返回到Idle状态。


本文来自网易实践者社区,经作者吴思博授权发布。