时间:2022-10-23 11:15:45 | 栏目:Android代码 | 点击:次
Android
多媒体框架支持播放提供了MediaPlayer
API,可以通过MediaPlayer
来实现媒体文件播放。可以说MediaPlayer
是非常方便使用的多媒体播放器,只需要简单设置就能实现对音频和视频播放功能,其内部帮助开发者实现了播放对象获取解码以及播放功能。
MediaPlayer
支持多种资源形式:本地资源、内部URI、外部网址。
//播放器实例化 mediaPlayer = new MediaPlayer(); //准备播放素材 Uri uri = Uri.fromFile(new File("sdcard/DCIM","Camera/test.mp4")); try { //播放器载入资源 mediaPlayer.setDataSource(this,uri); } catch (IOException e) { e.printStackTrace(); } //播放器异步准备 mediaPlayer.prepareAsync(); mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { //播放操作 mediaPlayer.start(); } }); //播放窗口展示 SurfaceView surfaceView = new SurfaceView(this); surfaceView.post(new Runnable() { @Override public void run() { mediaPlayer.setSurface(surfaceView.getHolder().getSurface()); } });
以上代码示例就是MediaPlayer
简单使用过程。其中prepareAsync()
是异步操作需要在回调setOnPreparedListener
方法了解最终播放器准备结果然后再执行播放操作。当然播放器也支持同步准备prepare
方法,但推荐使用异步操作,因为资源获取过程可能会涉及到解码数据会是耗时操作,同步操作很有可能造成ANR错误。
MediaPlayer
虽然有内部状态,某些操作只有在特定状态下正确操作才能生效。若在非指定状态下操作或许会导致播放器发生异常更有可能发生崩溃的情况。但播放器的内部状态机并没有暴露接口给开发者,无法随时能够获取到目前播放器当前状态。
因为缺陷原因直接使用MediaPlayer
就不能很好的去管理状态。因此可以自行对MediaPlayer
进行封装使用,可以将功能进行整理并且增加状态管理和方便错误统一处理等逻辑。
根据MediaPlayer
状态图预设几种状态类型以暂存播放器内部状态。
private static final int IDLE = 0; // 空闲状态 private static final int INIT = 3;// 初始化状态 private static final int PREPARING = 4;// 准备状态 private static final int PREPARED = 5;// 准备状态 private static final int STARTED = 6;// 开始状态 private static final int PAUSED = 7;// 暂停状态 private static final int STOPPED = 8;// 停止状态 private static final int END = 9; // 结束状态 private static final int ERROR = 10;// 错误状态
使用mPlayerStatus
暂存播放器状态
@IntDef({IDLE, END, ERROR, INIT, PREPARED, STARTED, PAUSED, STOPPED, }) public @interface STATUS { } MediaPlayer mMediaPlayer; Context mContext; @STATUS int mPlayerStatus = IDLE;
初始化函数实例化播放器并注册基本播放所需要的回调函数
public AndroidMediaPlayer(Context context) { mContext = context; mMediaPlayer = new MediaPlayer(); mMediaPlayer.setOnErrorListener(this); mMediaPlayer.setOnCompletionListener(this); mMediaPlayer.setOnPreparedListener(this); mPlayerStatus = INIT; }
封装播放器基础方法可供播放调用并且进行状态机判断,若不在可操作范围内则不可执行对应操作。同时对于资源设置方法通过原生api
可以看到有许多在形式,但这里就只是用URI
来做入参了。
//资源入参 public void setSource(Uri uri){ try { mMediaPlayer.setDataSource(mContext,uri); mMediaPlayer.prepareAsync(); mPlayerStatus = PREPARING; } catch (IOException e) { e.printStackTrace(); } } // 设置可视化窗口 public void setSurface(Surface surface){ mMediaPlayer.setSurface(surface); } //开始播放 public void start(){ mMediaPlayer.start(); mPlayerStatus = STARTED; } //暂停 public void pause(){ if(mPlayerStatus > PAUSED) return; mMediaPlayer.pause(); mPlayerStatus = PAUSED; } //停止 public void stop(){ if(mPlayerStatus > STOPPED) return; mMediaPlayer.stop(); mPlayerStatus = STOPPED; } //释放 public void release(){ if(mPlayerStatus >= INIT){ mMediaPlayer.release(); mMediaPlayer = null; mPlayerStatus = END; } } // 错误回调 @Override public boolean onError(MediaPlayer mp, int what, int extra) { mPlayerStatus = ERROR; return false; } // 播放回调 @Override public void onCompletion(MediaPlayer mp) { } // 准备成功回调 @Override public void onPrepared(MediaPlayer mp) { mPlayerStatus = PREPARED; }
MediaPlayer
作为官方提供封装的播放器在使用上并没有什么难度,可以说开发者直接开箱即用。或许对于简单开发视频播放已经足够了,能够播放本地文件或是网络文件等都能支持。但对于深入理解MediaPlayer
可能还远远不够,后续去读读源码来了解内部实现。之后要自行实现编解码来播放音视频等能力去处理和添加其他效果的时候,那时MediaPlayer
或许就捉襟见肘了。