深入Android MediaPlayer的使用方法详解
mediaPlayer = new MediaPlayer();mediaPlayer.setDataSource(path);
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
// 通过异步的方式装载媒体资源
mediaPlayer.prepareAsync();
mediaPlayer.setOnPreparedListener(new OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
// 装载完毕回调
mediaPlayer.start();
}
});
1)如何获得MediaPlayer实例:
可以使用直接new的方式:
MediaPlayer mp = new MediaPlayer();
也可以使用create的方式,如:
MediaPlayer mp = MediaPlayer.create(this, R.raw.test);//这时就不用调用setDataSource了
2) 如何设置要播放的文件:
MediaPlayer要播放的文件主要包括3个来源:
a. 用户在应用中事先自带的resource资源
例如:MediaPlayer.create(this, R.raw.test);
b. 存储在SD卡或其他文件路径下的媒体文件
例如:mp.setDataSource("/sdcard/test.mp3");
c. 网络上的媒体文件
例如:mp.setDataSource("http://www.citynorth.cn/music/confucius.mp3");
MediaPlayer的setDataSource一共四个方法:
setDataSource (String path)
setDataSource (FileDescriptor fd)
setDataSource (Context context, Uri uri)
setDataSource (FileDescriptor fd, long offset, long length)
其中使用FileDescriptor时,需要将文件放到与res文件夹平级的assets文件夹里,然后使用:
AssetFileDescriptor fileDescriptor = getAssets().openFd("rain.mp3");
m_mediaPlayer.setDataSource(fileDescriptor.getFileDescriptor(),fileDescriptor.getStartOffset(), fileDescriptor.getLength());
来设置datasource
3)对播放器的主要控制方法:
Android通过控制播放器的状态的方式来控制媒体文件的播放,其中:
prepare()和prepareAsync() 提供了同步和异步两种方式设置播放器进入prepare状态,需要注意的是,如果MediaPlayer实例是由create方法创建的,那么第一次启动播放前不需要再调用prepare()了,因为create方法里已经调用过了。
start()是真正启动文件播放的方法,
pause()和stop()比较简单,起到暂停和停止播放的作用,
seekTo()是定位方法,可以让播放器从指定的位置开始播放,需要注意的是该方法是个异步方法,也就是说该方法返回时并不意味着定位完成,尤其是播放的网络文件,真正定位完成时会触发OnSeekComplete.onSeekComplete(),如果需要是可以调用setOnSeekCompleteListener(OnSeekCompleteListener)设置监听器来处理的。
release()可以释放播放器占用的资源,一旦确定不再使用播放器时应当尽早调用它释放资源。
reset()可以使播放器从Error状态中恢复过来,重新会到Idle状态。
4)设置播放器的监听器:
MediaPlayer提供了一些设置不同监听器的方法来更好地对播放器的工作状态进行监听,以期及时处理各种情况,
如: setOnCompletionListener(MediaPlayer.OnCompletionListener listener)、
setOnErrorListener(MediaPlayer.OnErrorListener listener)等,设置播放器时需要考虑到播放器可能出现的情况设置好监听和处理逻辑,以保持播放器的健壮性。
Android MP3播放器MediaPlayer
前言
Android提供了常见的音频、视频的编码、解码机制。借助于多媒体类MediaPlayer的支持,开发人员可以很方便在在应用中播放音频、视频。本篇博客主要讲解在Android平台下如何播放一个音频文件。
本篇博客主要内容如下:
- MediaPlayer
- MediaPlayer的音频源
- 使用MediaPlayer播放音乐
- MediaPlayer使用技巧
- Demo--一个简单的MP3播放器
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.
1 mediaPlayer = new MediaPlayer();
2.
2 mediaPlayer.setDataSource(
"/sdcarc/a.mp3"
);
注意读内存卡,还需要设定访问内存卡的权限:
1.
<uses-permission android:name=
"android.permission.READ_EXTERNAL_STORAGE"
></uses-permission>
如,设置一个外部uri的网络流媒体资源:
1.
1 mediaPlayer = new MediaPlayer();
2.
2 mediaPlayer.setDataSource(http://192.168.1.102:1231/music/a.mp3);
如果访问网络流媒体资源,还需要设置访问网络的权限:
1.
<uses-permission android:name=
"android.permission.INTERNET"
></uses-permission>
使用MediaPlayer播放音乐
MediaPlayer其实是一个封装的很好的音频、视频流媒体操作类,如果查看其源码,会发现其内部是调用的native方法,所以它其实是有C++实现的。
既然是一个流媒体操作类,那么必然涉及到,播放、暂停、停止等操作,实际上MediaPlayer也为我们提供了相应的方法来直接操作流媒体。
- void statr():开始或恢复播放。
- 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 });
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
}
3、使用MediaPlayer最好使用一个Service来使用,并且在Service的onDestory()方法中回收MediaPlayer资源,实际上,就算是直接使用Activity承载MediaPlayer,也最好在销毁的时候判断一下MediaPlayer是否被回收,如果未被回收,回收其资源,因为底层调用的native方法,如果不销毁还是会在底层继续播放,而承载的组件已经被销毁了,这个时候就无法获取到这个MediaPlayer进而控制它。
- @Override
- protected void onDestroy() {
- if (mediaPlayer != null && mediaPlayer.isPlaying()) {
- mediaPlayer.stop();
- mediaPlayer.release();
- mediaPlayer = null;
- }
- super.onDestroy();
- }
01.
1 // 设置循环播放
02.
2 // mediaPlayer.setLooping(
true
);
03.
3 mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
04.
4
05.
5 @Override
06.
6 public void onCompletion(MediaPlayer mp) {
07.
7 // 在播放完毕被回调
08.
8 play();
09.
9 }
10.
10 });
1.
1 mediaPlayer.setOnErrorListener(new OnErrorListener() {
2.
2
3.
3 @Override
4.
4 public boolean onError(MediaPlayer mp, int what, int extra) {
5.
5 play();
6.
6
return
false
;
7.
7 }
8.
8 });
上面已经介绍了MediaPlayer播放一段音频文件的所有需要用到的内容。下面通过一个简单的Demo来演示如何使用MediaPlayer播放一个SD卡上的MP3文件。操作MediaPlayer应该放在Service中完成,这里为了简单,使用Activity直接操作MediaPlayer。代码注释里写的很清楚里,这里不再累述。
执行这个示例需要在/sdcard/目录下存在xm.mp3的文件。
private EditText et_path;
private Button btn_play, btn_pause, btn_replay, btn_stop;
private MediaPlayer mediaPlayer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et_path = (EditText) findViewById(R.id.et_path);
btn_play = (Button) findViewById(R.id.btn_play);
btn_pause = (Button) findViewById(R.id.btn_pause);
btn_replay = (Button) findViewById(R.id.btn_replay);
btn_stop = (Button) findViewById(R.id.btn_stop);
btn_play.setOnClickListener(click);
btn_pause.setOnClickListener(click);
btn_replay.setOnClickListener(click);
btn_stop.setOnClickListener(click);
}
private View.OnClickListener click = new View.OnClickListener() {
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_play:
play();
break;
case R.id.btn_pause:
pause();
break;
case R.id.btn_replay:
replay();
break;
case R.id.btn_stop:
stop();
break;
default:
break;
}
}
};
/**
* 播放音乐
*/
protected void play() {
String path = et_path.getText().toString().trim();
File file = new File(path);
if (file.exists() && file.length() > 0) {
try {
mediaPlayer = new MediaPlayer();
// 设置指定的流媒体地址
mediaPlayer.setDataSource(path);
// 设置音频流的类型
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
// 通过异步的方式装载媒体资源
mediaPlayer.prepareAsync();
mediaPlayer.setOnPreparedListener(new OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
// 装载完毕 开始播放流媒体
mediaPlayer.start();
Toast.makeText(MainActivity.this, "开始播放", 0).show();
// 避免重复播放,把播放按钮设置为不可用
btn_play.setEnabled(false);
}
});
// 设置循环播放
// mediaPlayer.setLooping(true);
mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
// 在播放完毕被回调
btn_play.setEnabled(true);
}
});
mediaPlayer.setOnErrorListener(new OnErrorListener() {
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
// 如果发生错误,重新播放
replay();
return false;
}
});
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(this, "播放失败", 0).show();
}
} else {
Toast.makeText(this, "文件不存在", 0).show();
}
}
/**
* 暂停
*/
protected void pause() {
if (btn_pause.getText().toString().trim().equals("继续")) {
btn_pause.setText("暂停");
mediaPlayer.start();
Toast.makeText(this, "继续播放", 0).show();
return;
}
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.pause();
btn_pause.setText("继续");
Toast.makeText(this, "暂停播放", 0).show();
}
}
/**
* 重新播放
*/
protected void replay() {
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.seekTo(0);
Toast.makeText(this, "重新播放", 0).show();
btn_pause.setText("暂停");
return;
}
play();
}
/**
* 停止播放
*/
protected void stop() {
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
btn_play.setEnabled(true);
Toast.makeText(this, "停止播放", 0).show();
}
}
@Override
protected void onDestroy() {
// 在activity结束的时候回收资源
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
}
super.onDestroy();
}
}
效果展示: