今天做了一个简易的音乐播放器程序,其实主要是运用一下MediaPlayer。
播放器有两个按钮,分别是播放和暂停;一个textview显示文件总时长;两个seekbar,分别是调节进度和音量大小。
设计思路:
1.运用MediaPlayer加载音乐文件。其中加载文件有好几种方式:
a.将音频文件拷贝到工程目录的文件夹中
mediaPlayer=mediaPlayer.create(this,R.raw.music );
或者
mediaPlayer.setDataSource(this,
// Uri.parse("android.resource://"+getPackageName()+"/"+R.raw.music));
b.从网络资源加载音频文件
mediaPlayer.setDataSource(this, Uri.parse("www.baidu.com/music.mp3"));
c.从sd卡中加载音频文件
String path=Environment.getExternalStorageDirectory().getAbsolutePath()+"/music.mp3";//动态拿到文件
mediaPlayer.setDataSource(path);//加载sd卡文件
这里注意:如果是用的setDataSource方法,调用这个方法后,音频文件并没有真正装载,而是还需要调用preper方法。细心可以发现,开始播放音频文件之后,即使关闭程序,即跳出activity。音频仍旧还在播放,因为mediaplayer和activity的生命周期无关。所以我们如果要实现跳出activity就关掉音频怎应该重写activity中的onDestroy方法,判断是否还在播放,然后stop。
protected void onDestroy() {//mediaplayer生命周期与activity生命周期无关,所以关闭activity也不会关闭音乐,所以需要重新设置属性
if(mediaPlayer!=null&&mediaPlayer.isPlaying()){
mediaPlayer.stop();
mediaPlayer.reset();//音乐播放涉及到硬件设备所以需要回收资源,变为空闲状态
mediaPlayer=null;
}
super.onDestroy();
}
其中preper方法也分同步加载和异步加载,分别是:
mediaPlayer.prepare();//同步加载方式
// mediaPlayer.prepareAsync();//异步加载方式
2.其中mediaplayer还有许多方法,这里用到的是设置播放模式,即循环播放,单曲循环,顺序播放等等;监听事件有出错事件监听和播放完成事件监听等等,播放完成事件监听可以实现播放下一曲的需求。但是播放完成事件监听事件若要实现,则循环模式必定要设置成false即不要单曲循环。
mediaPlayer.setLooping(false);//设置循环播放,true为循环,false不循环
// mediaPlayer.setOnErrorListener(new OnErrorListener() ;//出错事件监听
mediaPlayer.setOnCompletionListener(new OnCompletionListener() {//1.播放完成监听器,播放完成触发,2.而且不可循环即setlooping为false
public void onCompletion(MediaPlayer mp) {
Toast.makeText(MainActivity.this, "播放下一首", 0).show();
}
});
3.将文件总时长获取到并且加载到textview组件中。并且动态的设置进度条的最大值(获取文件的总时长–毫秒)
private void convert() {
time=mediaPlayer.getDuration()/1000;//得到总得秒数
mtime=time/60;
stime=time%60;
}
tv.setText(mtime+":"+stime);
jindu.setMax(mediaPlayer.getDuration());//设置进度条最大值,确保音频播放完进度条终止
4.这样音频文件加载成功,我们需要让seekbar进度条跟随文件的播放动起来。并且还能根据调节进度条来改变音频的播放进度。即断点播放。这时候需要用到子线程和handle机制了。
a.首先我们先让进度条跟随音频的播放动起来。在播放按钮的点击事件中,启动播放后,开启一个子线程,在一个循环中每隔1秒给handler发送一个消息。handler接受到消息之后,获取当前音频播放进度,再将其设置为进度条的进度。这样就让进度条随着音频播放动起来了。
private Handler handler=new Handler(){
//收到handler发回的消息时候回调
public void handleMessage(android.os.Message msg) {
if(msg.what==0x123){
jindu.setProgress(mediaPlayer.getCurrentPosition());
}
};
};
public void start(View view){
mediaPlayer.start();
new Thread(){
public void run() {
while(true){
handler.sendEmptyMessage(0x123);
try {
sleep(1000);//歌曲是一秒一秒播放,进度条也是这样走
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
}.start();
}
b.进度条随着音频的播放动起来,接下来实现音频的播放会随着进度条的调节而发生改变。即断点播放。此时需要给播放进度条设置点击事件:获取当前的进度条的进度,再 将其值赋给音频播放进度,从而使得音频随着进度条而发生改变。seekbar的点击事件中有三个方法,分别是触摸滑动停止,触摸滑动状态,触摸滑动开始。我需要的是在调节结束后音频会在我们抬手的地方开始播放,所以我们在触摸停止方法中实现。
jindu.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
public void onStopTrackingTouch(SeekBar seekBar) {
mediaPlayer.seekTo(jindu.getProgress());
}
public void onStartTrackingTouch(SeekBar seekBar) {
}
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
}
});
这样我们就实现了音频播放会随着进度条的改变而改变。
5.接下来还有调节音量的功能,此时用到的是一个AudioManger这个类,同样的,我们会对其设置一个最大值,确保音量不会无限增加。有方法可以获得当前系统所有的最大音量值。其中还有一个steamType参数表示的是音量类型,例如通话声音,系统声音,铃声声音等等,这我们选择铃声声音。当然我们还需要设置播放的初始音量,可以通过方法获得当前设备的音量。初始化好之后,我们队音量的seekbar设置点击事件:而此时和进度不一样的是,我们在调节过程中,可以明显感受到音量随着seekbar的改变而发生高低,所以这里我们选择在触摸状态发生改变方法中实现:
audioManager=(AudioManager) getSystemService(AUDIO_SERVICE);
yinliang.setMax(audioManager.getStreamMaxVolume(audioManager.STREAM_MUSIC));//获取设备最大音量,参数streamType是音量类型,例如通话声音,系统声音,铃声声音
yinliang.setProgress(audioManager.getStreamVolume(audioManager.STREAM_MUSIC));//设置初始音量
yinliang.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
public void onStopTrackingTouch(SeekBar seekBar) {
}
public void onStartTrackingTouch(SeekBar seekBar) {
}
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
audioManager.setStreamVolume(audioManager.STREAM_MUSIC, progress, audioManager.FLAG_SHOW_UI);//第三个参数表示调节是否有ui交互界面出现
}
});
这样一个简单的音频播放器就实现了,后期加上ui设计和添加需求会是的使用体验更好。
全部源码:
Mainactivity.class
public class MainActivity extends Activity {
private int time,mtime,stime;
private MediaPlayer mediaPlayer;
private SeekBar jindu,yinliang;
private TextView tv;
private AudioManager audioManager;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
jindu=(SeekBar) findViewById(R.id.jindu);
yinliang=(SeekBar) findViewById(R.id.yinliang);
tv=(TextView) findViewById(R.id.tv);
//实例了一个mediaplayer,并且装载了音乐
//mediaPlayer=mediaPlayer.create(this,R.raw.music );
mediaPlayer=new MediaPlayer();
try {
// mediaPlayer.setDataSource(this,
// Uri.parse("android.resource://"+getPackageName()+"/"+R.raw.music));
// mediaPlayer.setDataSource(this, Uri.parse("www.baidu.com/music.mp3"));//从网络资源加载
String path=Environment.getExternalStorageDirectory().getAbsolutePath()+"/music.mp3";//动态拿到文件
mediaPlayer.setDataSource(path);//加载sd卡文件
//如果是setDataSource需要调用完这个方法之后,音频文件并没有真正的真正装载,而是要调用preper方法
mediaPlayer.prepare();//同步加载方式
// mediaPlayer.prepareAsync();//异步加载方式
mediaPlayer.setLooping(false);//设置循环播放,true为循环,false不循环
// mediaPlayer.setOnErrorListener(new OnErrorListener() ;//出错事件监听
mediaPlayer.setOnCompletionListener(new OnCompletionListener() {//1.播放完成监听器,播放完成触发,2.而且不可循环即setlooping为false
public void onCompletion(MediaPlayer mp) {
Toast.makeText(MainActivity.this, "播放下一首", 0).show();
}
});
audioManager=(AudioManager) getSystemService(AUDIO_SERVICE);
yinliang.setMax(audioManager.getStreamMaxVolume(audioManager.STREAM_MUSIC));//获取设备最大音量,参数streamType是音量类型,例如通话声音,系统声音,铃声声音
yinliang.setProgress(audioManager.getStreamVolume(audioManager.STREAM_MUSIC));//设置初始音量
yinliang.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
public void onStopTrackingTouch(SeekBar seekBar) {
}
public void onStartTrackingTouch(SeekBar seekBar) {
}
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
audioManager.setStreamVolume(audioManager.STREAM_MUSIC, progress, audioManager.FLAG_SHOW_UI);
}
});
// mediaPlayer.prepareAsync();//异步加载方式
} catch (Exception e) {
e.printStackTrace();
}
convert();
tv.setText(mtime+":"+stime);
jindu.setMax(mediaPlayer.getDuration());
jindu.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
public void onStopTrackingTouch(SeekBar seekBar) {
mediaPlayer.seekTo(jindu.getProgress());
}
public void onStartTrackingTouch(SeekBar seekBar) {
}
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
}
});
}
private void convert() {
time=mediaPlayer.getDuration()/1000;//得到总得秒数
mtime=time/60;
stime=time%60;
}
protected void onDestroy() {//mediaplayer生命周期与activity生命周期无关,所以关闭activity也不会关闭音乐,所以需要重新设置属性
if(mediaPlayer!=null&&mediaPlayer.isPlaying()){
mediaPlayer.stop();
mediaPlayer.reset();//音乐播放涉及到硬件设备所以需要回收资源,变为空闲状态
mediaPlayer=null;
}
super.onDestroy();
}
private Handler handler=new Handler(){
//收到handler发回的消息时候回调
public void handleMessage(android.os.Message msg) {
if(msg.what==0x123){
jindu.setProgress(mediaPlayer.getCurrentPosition());
}
};
};
public void start(View view){
mediaPlayer.start();
new Thread(){
public void run() {
while(true){
handler.sendEmptyMessage(0x123);
try {
sleep(1000);//歌曲是一秒一秒播放,进度条也是这样走
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
}.start();
}
public void pause(View view){
mediaPlayer.pause();
}
}
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.verney.music.MainActivity" android:orientation="vertical">
<Button android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="start" android:text="播放"/>
<Button android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="pause" android:text="暂停"/>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/tv"/>
<SeekBar android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/jindu"/>
<SeekBar android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/yinliang"/>
</LinearLayout>