博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android--MP3播放器MediaPlayer
阅读量:5062 次
发布时间:2019-06-12

本文共 11566 字,大约阅读时间需要 38 分钟。

前言

  Android提供了常见的音频、视频的编码、解码机制。借助于多媒体类MediaPlayer的支持,开发人员可以很方便在在应用中播放音频、视频。本篇博客主要讲解在Android平台下如何播放一个音频文件。

  本篇博客主要内容如下:

  

MediaPlayer

  上面提到过,Android下对于音频、视频的支持均需要使用到MediaPlayer,它主要用来控制Android下播放文件或流的类。MediaPlayer处于Android多媒体包下"android.media.MediaPlayer",仅有一个无参的构造函数,虽然仅为我们提供了一个无参的构造函数,为了方便我们初始化,还为我们提供了几个静态的create()方法用于完成MediaPlayer初始化的工作。

  • static MediaPlayer create(Context context,int resid):通过音频资源的Id来创建一个MediaPlayer实例。
  • static MediaPlayer create(Context context,Uri uri):通过一个音频资源的Uri地址来创建一个MediaPlayer实例。

  MediaPlayer除了通过上面两个create()方法在初始化的时候指定媒体资源,还可以通过MediaPlayer.setDataSource()方法为初始化后的MediaPlayer设置媒体资源,setDataSource()具有多个重载函数,适用于不同的媒体资源来源,以下讲解几个常用的,其他的可以查阅官方文档。

  • void setDataSource(String path):通过一个媒体资源的地址指定MediaPlayer的数据源,这里的path可以是一个本地路径,也可以是网络路径。
  • void setDataSource(Context context,Uri uri):通过一个Uri指定MediaPlayer的数据源,这里的Uri可以是网络路径或这一个内容提供者的Uri。
  • void setDataSource(FileDescriptor fd):通过一个FileDescriptor指定一个MediaPlayer的数据源。

 

MediaPlayer的音频源

  通过上面介绍的初始化MediaPlayer的播放时媒体数据源的方法可以看出,MediaPlayer支持的数据源有:本地文件、内部的Uri(内容提供者)、外部Uri。

  如,设置一个本地SD卡的资源:

1                 mediaPlayer = new MediaPlayer();2                 mediaPlayer.setDataSource("/sdcarc/a.mp3");

  注意读内存卡,还需要设定访问内存卡的权限:

  如,设置一个外部uri的网络流媒体资源:

1                 mediaPlayer = new MediaPlayer();2                 mediaPlayer.setDataSource();

  如果访问网络流媒体资源,还需要设置访问网络的权限:

 

 

使用MediaPlayer播放音乐

  MediaPlayer其实是一个封装的很好的音频、视频流媒体操作类,如果查看其源码,会发现其内部是调用的native方法,所以它其实是有C++实现的。

  既然是一个流媒体操作类,那么必然涉及到,播放、暂停、停止等操作,实际上MediaPlayer也为我们提供了相应的方法来直接操作流媒体。

  • void start():开始或恢复播放。
  • void stop():停止播放。
  • void pause():暂停播放。  

  通过上面三个方法,只要设定好流媒体数据源,即可在应用中播放流媒体资源,为了更好的操作流媒体,MediaPlayer还为我们提供了一些其他的方法,这里列出一些常用的,详细内容参阅官方文档。

  • int getDuration():获取流媒体的总播放时长,单位是毫秒。
  • int getCurrentPosition():获取当前流媒体的播放的位置,单位是毫秒。
  • void seekTo(int msec):设置当前MediaPlayer的播放位置,单位是毫秒。
  • void setLooping(boolean looping):设置是否循环播放。
  • boolean isLooping():判断是否循环播放。
  • boolean  isPlaying():判断是否正在播放。
  • void prepare():同步的方式装载流媒体文件。
  • void prepareAsync():异步的方式装载流媒体文件。
  • void release ():回收流媒体资源。 
  • void setAudioStreamType(int streamtype):设置播放流媒体类型。
  • void setWakeMode(Context context, int mode):设置CPU唤醒的状态。
  • setNextMediaPlayer(MediaPlayer next):设置当前流媒体播放完毕,下一个播放的MediaPlayer。

  大部分方法的看方法名就可以理解,但是有几个方法需要单独说明一下。

  在使用MediaPlayer播放一段流媒体的时候,需要使用prepare()或prepareAsync()方法把流媒体装载进MediaPlayer,才可以调用start()方法播放流媒体。                 

  setAudioStreamType()方法用于指定播放流媒体的类型,它传递的是一个int类型的数据,均以常量定义在AudioManager类中, 一般我们播放音频文件,设置为AudioManager.STREAM_MUSIC即可。

  

  除了上面介绍的一些方法外,MediaPlayer还提供了一些事件的回调函数,这里介绍几个常用的:

  • setOnCompletionListener(MediaPlayer.OnCompletionListener listener):当流媒体播放完毕的时候回调。
  • setOnErrorListener(MediaPlayer.OnErrorListener listener):当播放中发生错误的时候回调。
  • setOnPreparedListener(MediaPlayer.OnPreparedListener listener):当装载流媒体完毕的时候回调。
  • setOnSeekCompleteListener(MediaPlayer.OnSeekCompleteListener listener):当使用seekTo()设置播放位置的时候回调。

 

MediaPlayer使用技巧

  在使用MediaPlayer的使用过程中,有个小技巧需要说明一下:

  1、在使用start()播放流媒体之前,需要装载流媒体资源。这里最好使用prepareAsync()用异步的方式装载流媒体资源。因为流媒体资源的装载是会消耗系统资源的,在一些硬件不理想的设备上,如果使用prepare()同步的方式装载资源,可能会造成UI界面的卡顿,这是非常影响用于体验的。因为推荐使用异步装载的方式,为了避免还没有装载完成就调用start()而报错的问题,需要绑定MediaPlayer.setOnPreparedListener()事件,它将在异步装载完成之后回调。异步装载还有一个好处就是避免装载超时引发ANR((Application Not Responding)错误。

1                 mediaPlayer = new MediaPlayer(); 2                 mediaPlayer.setDataSource(path); 3                 mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); 4                  5                 // 通过异步的方式装载媒体资源 6                 mediaPlayer.prepareAsync(); 7                 mediaPlayer.setOnPreparedListener(new OnPreparedListener() {                     8                     @Override 9                     public void onPrepared(MediaPlayer mp) {10                         // 装载完毕回调11                         mediaPlayer.start();12                     }13                 });

  2、使用完MediaPlayer需要回收资源。MediaPlayer是很消耗系统资源的,所以在使用完MediaPlayer,不要等待系统自动回收,最好是主动回收资源。

1         if (mediaPlayer != null && mediaPlayer.isPlaying()) {2             mediaPlayer.stop();3             mediaPlayer.release();4             mediaPlayer = null;5         }

  3、使用MediaPlayer最好使用一个Service来使用,并且在Service的onDestory()方法中回收MediaPlayer资源,实际上,就算是直接使用Activity承载MediaPlayer,也最好在销毁的时候判断一下MediaPlayer是否被回收,如果未被回收,回收其资源,因为底层调用的native方法,如果不销毁还是会在底层继续播放,而承载的组件已经被销毁了,这个时候就无法获取到这个MediaPlayer进而控制它。

1     @Override2     protected void onDestroy() {3         if (mediaPlayer != null && mediaPlayer.isPlaying()) {4             mediaPlayer.stop();5             mediaPlayer.release();6             mediaPlayer = null;7         }8         super.onDestroy();9     }

  4、对于单曲循环之类的操作,除了可以使用setLooping()方法进行设置之外,还可以为MediaPlayer注册回调函数,MediaPlayer.setOnCompletionListener(),它会在MediaPlayer播放完毕被回调。

1                 // 设置循环播放 2 //                mediaPlayer.setLooping(true); 3                 mediaPlayer.setOnCompletionListener(new OnCompletionListener() { 4                      5                     @Override 6                     public void onCompletion(MediaPlayer mp) { 7                         // 在播放完毕被回调 8                         play();                         9                     }10                 });

   5、因为MediaPlayer一直操作的是一个流媒体,所以无可避免的可能一段流媒体资源,前半段可以正常播放,而中间一段因为解析或者源文件错误等问题,造成中间一段无法播放问题,需要我们处理这个错误,否则会影响Ux(用户体验)。可以为MediaPlayer注册回调函数setOnErrorListener()来设置出错之后的解决办法,一般重新播放或者播放下一个流媒体即可。  

1                 mediaPlayer.setOnErrorListener(new OnErrorListener() {2                     3                     @Override4                     public boolean onError(MediaPlayer mp, int what, int extra) {5                         play();6                         return false;7                     }8                 });

 

 

Demo--一个简单的MP3播放器

  上面已经介绍了MediaPlayer播放一段音频文件的所有需要用到的内容。下面通过一个简单的Demo来演示如何使用MediaPlayer播放一个SD卡上的MP3文件。操作MediaPlayer应该放在Service中完成,这里为了简单,使用Activity直接操作MediaPlayer。代码注释里写的很清楚里,这里不再累述。

  执行这个示例需要在/sdcard/目录下存在xm.mp3的文件。  

1 package cn.bgxt.mediaplayerdemo;  2   3 import java.io.File;  4 import android.media.AudioManager;  5 import android.media.MediaPlayer;  6 import android.media.MediaPlayer.OnCompletionListener;  7 import android.media.MediaPlayer.OnErrorListener;  8 import android.media.MediaPlayer.OnPreparedListener;  9 import android.os.Bundle; 10 import android.app.Activity; 11 import android.view.View; 12 import android.widget.Button; 13 import android.widget.EditText; 14 import android.widget.Toast; 15  16 public class MainActivity extends Activity { 17     private EditText et_path; 18     private Button btn_play, btn_pause, btn_replay, btn_stop; 19     private MediaPlayer mediaPlayer; 20  21     @Override 22     protected void onCreate(Bundle savedInstanceState) { 23         super.onCreate(savedInstanceState); 24         setContentView(R.layout.activity_main); 25  26         et_path = (EditText) findViewById(R.id.et_path); 27         btn_play = (Button) findViewById(R.id.btn_play); 28         btn_pause = (Button) findViewById(R.id.btn_pause); 29         btn_replay = (Button) findViewById(R.id.btn_replay); 30         btn_stop = (Button) findViewById(R.id.btn_stop); 31  32         btn_play.setOnClickListener(click); 33         btn_pause.setOnClickListener(click); 34         btn_replay.setOnClickListener(click); 35         btn_stop.setOnClickListener(click); 36     } 37  38     private View.OnClickListener click = new View.OnClickListener() { 39  40         @Override 41         public void onClick(View v) { 42  43             switch (v.getId()) { 44             case R.id.btn_play: 45                 play(); 46                 break; 47             case R.id.btn_pause: 48                 pause(); 49                 break; 50             case R.id.btn_replay: 51                 replay(); 52                 break; 53             case R.id.btn_stop: 54                 stop(); 55                 break; 56             default: 57                 break; 58             } 59         } 60     }; 61     /** 62      * 播放音乐 63      */ 64     protected void play() { 65         String path = et_path.getText().toString().trim(); 66         File file = new File(path); 67         if (file.exists() && file.length() > 0) { 68             try { 69                 mediaPlayer = new MediaPlayer(); 70                 // 设置指定的流媒体地址 71                 mediaPlayer.setDataSource(path); 72                 // 设置音频流的类型 73                 mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); 74  75                 // 通过异步的方式装载媒体资源 76                 mediaPlayer.prepareAsync(); 77                 mediaPlayer.setOnPreparedListener(new OnPreparedListener() { 78                     @Override 79                     public void onPrepared(MediaPlayer mp) { 80                         // 装载完毕 开始播放流媒体 81                         mediaPlayer.start(); 82                         Toast.makeText(MainActivity.this, "开始播放", 0).show(); 83                         // 避免重复播放,把播放按钮设置为不可用 84                         btn_play.setEnabled(false); 85                     } 86                 }); 87                 // 设置循环播放 88                 // mediaPlayer.setLooping(true); 89                 mediaPlayer.setOnCompletionListener(new OnCompletionListener() { 90  91                     @Override 92                     public void onCompletion(MediaPlayer mp) { 93                         // 在播放完毕被回调 94                         btn_play.setEnabled(true); 95                     } 96                 }); 97  98                 mediaPlayer.setOnErrorListener(new OnErrorListener() { 99 100                     @Override101                     public boolean onError(MediaPlayer mp, int what, int extra) {102                         // 如果发生错误,重新播放103                         replay(); 104                         return false;105                     }106                 });107             } catch (Exception e) {108                 e.printStackTrace();109                 Toast.makeText(this, "播放失败", 0).show();110             }111         } else {112             Toast.makeText(this, "文件不存在", 0).show();113         }114 115     }116     /**117      * 暂停118      */119     protected void pause() {120         if (btn_pause.getText().toString().trim().equals("继续")) {121             btn_pause.setText("暂停");122             mediaPlayer.start();123             Toast.makeText(this, "继续播放", 0).show();124             return;125         }126         if (mediaPlayer != null && mediaPlayer.isPlaying()) {127             mediaPlayer.pause();128             btn_pause.setText("继续");129             Toast.makeText(this, "暂停播放", 0).show();130         }131 132     }133     134     /**135      * 重新播放136      */137     protected void replay() {138         if (mediaPlayer != null && mediaPlayer.isPlaying()) {139             mediaPlayer.seekTo(0);140             Toast.makeText(this, "重新播放", 0).show();141             btn_pause.setText("暂停");142             return;143         }        144         play();145     }146     147     /**148      * 停止播放149      */150     protected void stop() {151         if (mediaPlayer != null && mediaPlayer.isPlaying()) {152             mediaPlayer.stop();153             mediaPlayer.release();154             mediaPlayer = null;155             btn_play.setEnabled(true);156             Toast.makeText(this, "停止播放", 0).show();157         }158 159     }160 161     @Override162     protected void onDestroy() {163         // 在activity结束的时候回收资源164         if (mediaPlayer != null && mediaPlayer.isPlaying()) {165             mediaPlayer.stop();166             mediaPlayer.release();167             mediaPlayer = null;168         }169         super.onDestroy();170     }171 }

 

  效果展示:

 

  

 

  

 

转载于:https://www.cnblogs.com/plokmju/p/android_MediaPlayer.html

你可能感兴趣的文章
栈和队列的方法
查看>>
GC模式
查看>>
JavaMail与Spring整合
查看>>
The user specified as a definer ('root'@'%') does not exist 解决方法 权限问题
查看>>
IDEA
查看>>
java基础知识起步
查看>>
Python学习笔记
查看>>
python笔记
查看>>
构建之法--探索篇(二)
查看>>
浅析软件开发的3个层次
查看>>
【1】
查看>>
perl中如何将按hash值排序
查看>>
铁乐学python_Day44_IO多路复用
查看>>
mysql check约束无效
查看>>
自然语言也支持泛型
查看>>
Chart
查看>>
查看版本信息的命令
查看>>
安装 SQLManagementStudio_x86_CHS(SQL Server Management Studio) 老提示重启的解决办法
查看>>
asp.net要验证的用户名和密码
查看>>
你的pip是时候出问题了吧
查看>>