上一篇说到音频录制的时候我就知道肯定会有音频播放这个功能,果不其然后续播放的需求又给我加上了,因为之前是AMR格式,所以这里使用MediaPlayer进行播放,据ios说播放amr格式的音频还挺麻烦的。

我已经把MediaPlayer写成工具类上传到Github中具体的使用方法可以查看Wiki,如果你想直接使用导入依赖即可,如果你不想去Github想直接修改或者自定义其他方法直接下载 mediaplaylib (提取码: xnv5) 即可

一、添加必要权限

//有播放网络资源的需要添加网络权限。
 <uses-permission android:name="android.permission.INTERNET"/> 
//播放本地资源需要添加SD卡权限,一般存储我都会全加上。 
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> 
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 
//在播放时有特殊设置的需要声明一个相应的WAKE_LOCK权限 
<uses-permission android:name="android.permission.WAKE_LOCK"/>

二、MediaPlayer 介绍

1.状态图

音频/视频文件和流的播放控制作为状态机进行管理。下图显示了受支持的播放控制操作驱动的 MediaPlayer 对象的生命周期和状态。椭圆形表示 MediaPlayer 对象可能驻留的状态。弧形表示驱动对象状态转换的回放控制操作。有两种类型的弧。具有单箭头的弧表示同步方法调用,而具有双箭头的弧表示异步方法调用。

MediaPlayer状态图

具体信息可以去Android官网阅读

2.MediaPlayer公开方法

方法有很多,这里只说常用的几个方法,其他的去Android官网查阅。

公开方法
static  MediaPlayer create(Context context, int resid )为给定资源ID创建MediaPlayer的便捷方法,一般播放Raw下资源会使用此方法。
void setDataSource (AssetFileDescriptor afd)
setDataSource (FileDescriptor fd)
setDataSource (String path)
setDataSource (MediaDataSource dataSource)
setDataSource (Context context, Uri uri)

设置数据源,这里可以设置 AssetFileDescriptor 、 FileDescriptor 、 文件路径或http / rtsp URL 、 MediaDataSource 、 Uri

void prepare()
同步准备播放器以进行播放。
void prepareAsync()
准备播放器异步播放。
void pause()
暂停播放。
void release()
释放与此MediaPlayer对象关联的资源。
void reset()
将MediaPlayer重置为其未初始化状态。
void start()
开始或继续播放。
void stop()
开始或暂停播放后停止播放。
void setVolume(float leftVolume, float rightVolume)
设置播放的音量,左右声道取值 0~1。
void setOnCompletionListener(MediaPlayer. OnCompletionListener listener)
播放完成后的回调。
void setOnBufferingUpdateListener(MediaPlayer.OnBufferingUpdateListener listener)
网络流缓冲区的状态更改时的回调。
void setOnErrorListener(MediaPlayer.OnErrorListener listener)
错误回调。
void setOnInfoListener(MediaPlayer.OnInfoListener listener)
注册一个在信息/警告可用时要调用的回调。
void setOnPreparedListener(MediaPlayer.OnPreparedListener listener)
注册当媒体源准备好播放时要调用的回调。
void setOnSeekCompleteListener(MediaPlayer.OnSeekCompleteListener listener)
指定播放位置后的回调。
boolean isLooping()
检查MediaPlayer是循环还是非循环。
boolean isPlaying()
检查MediaPlayer是否正在播放。
void seekTo(long msec)
播放指定的时间位置。
void setScreenOnWhilePlaying(boolean screenOn)
控制在播放时是否熄屏。

三、代码编写

这里有个需要注意的地方:一般加载比较小的资源时候可以使用prepare(),但是如果你加载资源比较大的或者是网络资源的时候就是一个耗时操作,我们都知道不能在主线程执行耗时操作,所以就需要使用prepareAsync()配合setOnPreparedListener()在准备完成后自动播放音频。
如果你不信这个邪你可以用prepare()加载网络资源试试。


/**
 * 设置播放类型,之后调用stop方便切换类型。
 */

  private int PLAY_STATE = -1;//判断是什么类型
  public static final int PLAY_STATE0 = 1;//文件
  public static final int PLAY_STATE1 = 2;//raw
  public static final int PLAY_STATE2 = 3;//assets
  public static final int PLAY_STATE3 = 4;//网络

  private MediaPlayer mMediaPlayer = null;

  //设置不同的回调
  private MediaPlayFunctionListener mediaPlayFunctionListener;
  private MediaPlayInfoListener mMediaPlayInfoListener;

  //设置文件路径
  public void setFilePlay(File file) {
    this.targetFile = file;
    PLAY_STATE = PLAY_STATE0;
    stop();
  }
  //设置Raw播放
  public void setRawPlay(Context context,int rawId){
    this.mContext = context;
    this.rawId = rawId;
    PLAY_STATE = PLAY_STATE1;
    stop();
  }
  //设置Assets播放
  public void setAssetsName(Context context,String assetsName) {
    this.mContext = context;
    this.assetsName = assetsName;
    PLAY_STATE = PLAY_STATE2;
    stop();
  }
  //设置网络资源播放
  public void setNetPath(String netPath) {
    this.netPath = netPath;
    PLAY_STATE = PLAY_STATE3;
    stop();
  }

  //开始播放
  public boolean start() {
    if (PLAY_STATE == PLAY_STATE1){
      mMediaPlayer = MediaPlayer.create(mContext,rawId);
    }else {
      mMediaPlayer = new MediaPlayer();
    }
    try {
      switch (PLAY_STATE){
        case PLAY_STATE0://本地文件为数据源传入路径
          mMediaPlayer.setDataSource(targetFile.getAbsolutePath());
          mMediaPlayer.prepare();
          break;
        case PLAY_STATE1://如果raw为数据源则不处理
          break;
        case PLAY_STATE2://Assets下文件为数据源
          AssetFileDescriptor fileDescriptor = mContext.getAssets().openFd(assetsName);
          mMediaPlayer.setDataSource(fileDescriptor.getFileDescriptor(),fileDescriptor.getStartOffset(),fileDescriptor.getLength());
          mMediaPlayer.prepare();
          break;
        case PLAY_STATE3://网络数据源 设置网络连接
          mMediaPlayer.setDataSource(netPath);
          mMediaPlayer.prepareAsync();
          break;
      }
      //播放完成自动停止
      mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
        @Override public void onCompletion(MediaPlayer mediaPlayer) {
          //停止播放
          mediaPlayer.stop();
          //回调停止播放的方法。
          if (mediaPlayFunctionListener != null)
            mediaPlayFunctionListener.stop();
          //回调播放完成的方法
          if (mMediaPlayInfoListener != null)
            mMediaPlayInfoListener.onCompletion(mediaPlayer);
        }
      });
      //准备完毕 自动播放
      mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
        @Override public void onPrepared(MediaPlayer mediaPlayer) {
          mediaPlayer.start();
          //准备完毕,回调准备和开始方法
          if (mediaPlayFunctionListener != null) {
            mediaPlayFunctionListener.prepared();
            mediaPlayFunctionListener.start();
          }
        }
      });
      //播放错误监听
      mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
        @Override public boolean onError(MediaPlayer mp, int what, int extra) {
          //回调错误方法
          if (mMediaPlayInfoListener != null) {
            mMediaPlayInfoListener.onError(mp, what, extra);
          }
          //回调停止方法
          if (mMediaPlayer != null)
            stop();
          return false;
        }
      });
      //网络缓冲监听
      mMediaPlayer.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() {
        @Override public void onBufferingUpdate(MediaPlayer mp, int percent) {
          //回调网络缓冲方法
          if (mMediaPlayInfoListener != null)
            mMediaPlayInfoListener.onBufferingUpdate(mp,percent);
        }
      });
      //调整进度监听
      mMediaPlayer.setOnSeekCompleteListener(new MediaPlayer.OnSeekCompleteListener() {
        @Override public void onSeekComplete(MediaPlayer mp) {
          //回调调整进度后的方法,这里只有调整播放位置后才会调用
          if (mMediaPlayInfoListener != null)
            mMediaPlayInfoListener.onSeekComplete(mp);
        }
      });
    } catch (IOException e) {
      e.printStackTrace();
      mMediaPlayer.stop();
      mMediaPlayer.reset();
      mMediaPlayer.release();
      mMediaPlayer = null;
    }
    boolean result = (mMediaPlayer != null);
    this.isPlaying = result;
    return result;
  }
//停止播放
  public void stop() {
    this.isPlaying = false;
    this.duration = 0;

    if (mMediaPlayer != null) {
      mHandler.removeCallbacks(mRunnable);
      mMediaPlayer.stop();
      mMediaPlayer.reset();
      if (mediaPlayFunctionListener != null)
        mediaPlayFunctionListener.reset();
      mMediaPlayer.release();
      mMediaPlayer = null;
    }
  }

  //resume调用 继续播放也调用此方法即可
  public void resume() {
    if (mMediaPlayer != null) {
      this.isPlaying = true;
      mHandler.postDelayed(mRunnable,sleep);
      mMediaPlayer.start();
    }
  }

  //暂停
  public void pause() {
    this.isPlaying = false;
    mHandler.removeCallbacks(mRunnable);
    if (mMediaPlayer != null) {
      mMediaPlayer.pause();
      if (mediaPlayFunctionListener != null)
        mediaPlayFunctionListener.pause();
    }
  }
说点什么
支持Markdown语法
好耶,沙发还空着ヾ(≧▽≦*)o
Loading...