在Android中播放音频文件一般都是使用MediaPlayer类来实现的,它对多种格式的音频文件提供了非常全面的控制方法,从而使得播放音乐的工作变得非常简单。
从上图可以清楚的看出MediaPlayer的工作流程。
首先创建一个MediaPlayer对象,然后调用setDataSource()方法来设置音频播放的路径,再调用prepare()方法使MediaPlayer进行准备状态,接下来调用start()方法就可以开始播放音频,调用pause()方法就可以暂停播放,调用reset()方法就会停止播放。
下面我们写一个简单的音乐播放器,实现一些简单的功能,来深入理解MediaPlayer的用法。
注意:在我们向模拟器中导入歌曲的时候,不能有中午的歌曲名,否则导入失败!
首先搭建我们的主界面:
<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:orientation="vertical" tools:context=".MainActivity">
<ListView android:id="@+id/listview" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"></ListView>
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="10dp" android:orientation="horizontal">
<TextView android:id="@+id/currenttime" android:layout_width="wrap_content" android:layout_height="wrap_content" />
<SeekBar android:id="@+id/seekbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1"/>
<TextView android:id="@+id/totalttime" android:layout_width="wrap_content" android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#FFFFFF" android:orientation="horizontal" android:gravity="center">
<ImageButton android:id="@+id/last" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@mipmap/before"/>
<ImageButton android:id="@+id/play" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/play"/>
<ImageButton android:id="@+id/next" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@mipmap/next"/>
</LinearLayout>
</LinearLayout>
接下来是Drawable文件夹的内容,我们为播放,暂停按钮设置两种不同的转换!
play.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@mipmap/pause" android:state_checked="true"></item>
<item android:drawable="@mipmap/play"></item>
</selector>
pause.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@mipmap/play" android:state_checked="true"></item>
<item android:drawable="@mipmap/pause"></item>
</selector>
接下来,为我们的ListView设置布局,展示专辑图片,歌名和歌手名
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal">
<ImageView android:id="@+id/imageview" android:layout_width="50dp" android:layout_height="50dp" android:layout_margin="10dp"/>
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="10dp" android:orientation="vertical">
<TextView android:id="@+id/textview_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="name"/>
<TextView android:id="@+id/textview_artist" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:text="name"/>
</LinearLayout>
</LinearLayout>
然后为我们的歌曲列表写一个适配器MusicAdapter
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.MediaMetadataRetriever;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.io.File;
/** * Created by Administrator on 2015/9/10. */
public class MusicAdapter extends BaseAdapter{
private LayoutInflater inflater;
private File[] musics;
public MusicAdapter(File[] musics, LayoutInflater inflater) {
this.musics = musics;
this.inflater = inflater;
}
@Override
public int getCount() {
return musics.length;
}
@Override
public Object getItem(int position) {
return position;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view;
ViewHolder viewHolder;
if(convertView==null){
view=inflater.inflate(R.layout.musiclist,null);
viewHolder=new ViewHolder();
viewHolder.imageView= (ImageView) view.findViewById(R.id.imageview);
viewHolder.textView_name= (TextView) view.findViewById(R.id.textview_name);
viewHolder.textView_artist= (TextView) view.findViewById(R.id.textview_artist);
view.setTag(viewHolder);
}else{
view=convertView;
viewHolder= (ViewHolder) view.getTag();
}
MediaMetadataRetriever mediaMetadataRetriever=new MediaMetadataRetriever();
mediaMetadataRetriever.setDataSource(musics[position].getAbsolutePath());
byte[] image=mediaMetadataRetriever.getEmbeddedPicture();//得到歌曲的专辑图片
if (image!=null){
Bitmap bitmap= BitmapFactory.decodeByteArray(image,0,image.length);
viewHolder.imageView.setImageBitmap(bitmap);
}else {
viewHolder.imageView.setImageResource(R.mipmap.ic_launcher);
}
String artist=mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST);//得到歌曲的歌手名
if (artist!=null){
viewHolder.textView_artist.setText(artist);}
else {
viewHolder.textView_artist.setText("<未知>");
}
viewHolder.textView_name.setText(musics[position].getName());//设置歌曲名
return view;
}
class ViewHolder{
ImageView imageView;
TextView textView_name;
TextView textView_artist;
}
}
然后定义一个我们自己的常量类Config
/** * Created by Administrator on 2015/9/10. */
public class Config {
public static final int TOTAL_TIME=0;
public static final int CURRENT_TIME=1;
public static final int START_MUSIC=0;
public static final int PAUSE_MUSIC=1;
public static final int SEEK_TO=2;
public static final String BROADCAST_TAG="com.music.play";
public static final String TYPE="type";
public static final String TIME="time";
public static final String PATH="musicpath";
public static final String PROGRESS="progress";
}
接着写一个播放音乐的服务类,所有关于音乐播放的内容都放在这个服务中
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.IBinder;
import android.support.annotation.Nullable;
import java.io.IOException;
/** * Created by Administrator on 2015/9/10. */
public class MusicService extends Service{
private MediaPlayer mediaPlayer;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
int type=intent.getIntExtra(Config.TYPE, 0);
switch (type){
case Config.START_MUSIC://播放音乐
String musicPath=intent.getStringExtra(Config.PATH);
if (mediaPlayer==null){
mediaPlayer=new MediaPlayer();
}
mediaPlayer.reset();
try {
mediaPlayer.setDataSource(musicPath);
mediaPlayer.prepare();
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
mp.start();
int totalTime=mp.getDuration();//得到总时间
Intent intent=new Intent(Config.BROADCAST_TAG);
intent.putExtra(Config.TYPE,Config.TOTAL_TIME);
intent.putExtra(Config.TIME,totalTime);//将歌曲总时间传回去
sendBroadcast(intent);
new MusicplayerThread().start();
}
});
} catch (IOException e) {
e.printStackTrace();
}
break;
case Config.PAUSE_MUSIC://暂停歌曲
if(mediaPlayer.isPlaying()){
mediaPlayer.pause();
}else {
mediaPlayer.start();
new MusicplayerThread().start();
}
break;
case Config.SEEK_TO://拖动SeekBar,设置播放进度
int progress=intent.getIntExtra(Config.PROGRESS,0);//得到拖动位置
mediaPlayer.seekTo(progress);
break;
default:
break;
}
return super.onStartCommand(intent, flags, startId);
}
class MusicplayerThread extends Thread{
@Override
public void run() {
while (mediaPlayer.isPlaying()){
int currentTime=mediaPlayer.getCurrentPosition();//得到当前播放时间
Intent intent=new Intent(Config.BROADCAST_TAG);
intent.putExtra(Config.TYPE,Config.CURRENT_TIME);
intent.putExtra(Config.TIME,currentTime);//将当前播放时间传回去
sendBroadcast(intent);
try {
Thread.sleep(1000);//休眠,不让消息发送太频繁
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
@Override
public void onDestroy() {
super.onDestroy();
if(mediaPlayer!=null){
mediaPlayer.stop();
mediaPlayer.release();//释放相关资源
}
}
}
然后不要忘了在applica标签下注册我们的服务!
<service android:name=".MusicService"></service>
最后就是我们主活动中的代码:
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
import java.io.File;
import java.text.SimpleDateFormat;
public class MainActivity extends Activity {
private MyMusicBroadcastReceicer myMusicBroadcastReceicer;
private SeekBar seekBar;
private TextView textView_totaltime;
private TextView textView_currenttime;
private boolean isPlay;
private boolean isPause;
private boolean isFirstClick = true;
private ImageButton button_play;
private int listposition;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//File musicFile= Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC);
File file = Environment.getExternalStorageDirectory();
File musicFile = new File(file, "/Music");
final File[] files = musicFile.listFiles();//得到Music文件夹下所有文件
MusicAdapter adapter = new MusicAdapter(files, getLayoutInflater());
final ListView listView = (ListView) findViewById(R.id.listview);
seekBar = (SeekBar) findViewById(R.id.seekbar);
textView_totaltime = (TextView) findViewById(R.id.totalttime);
textView_currenttime = (TextView) findViewById(R.id.currenttime);
listView.setAdapter(adapter);
myMusicBroadcastReceicer = new MyMusicBroadcastReceicer();
IntentFilter intentFilter = new IntentFilter(Config.BROADCAST_TAG);
registerReceiver(myMusicBroadcastReceicer, intentFilter);//动态注册广播
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {//点击ListView播放当前选中歌曲
button_play.setBackgroundResource(R.drawable.pause);
isFirstClick=false;
isPlay=true;
isPause=false;
listposition=position;//得到当前选中位置
Intent intent = new Intent(getApplicationContext(), MusicService.class);
intent.putExtra(Config.TYPE, Config.START_MUSIC);
intent.putExtra(Config.PATH, files[position].getAbsolutePath());
startService(intent);
}
});
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
Intent intent = new Intent(getApplicationContext(), MusicService.class);
intent.putExtra(Config.TYPE, Config.SEEK_TO);
intent.putExtra(Config.PROGRESS, seekBar.getProgress());//传回拖动位置
startService(intent);
}
});
ImageButton button_last = (ImageButton) findViewById(R.id.last);
button_last.setOnClickListener(new View.OnClickListener() {//播放上一首歌
@Override
public void onClick(View v) {
listposition=listposition-1;
button_play.setBackgroundResource(R.drawable.pause);
isFirstClick=false;
isPlay = true;
isPause = false;
if(listposition>=0){
Intent intent = new Intent(getApplicationContext(), MusicService.class);
intent.putExtra(Config.TYPE, Config.START_MUSIC);
intent.putExtra(Config.PATH, files[listposition].getAbsolutePath());
startService(intent);
}else {
Toast.makeText(getApplicationContext(), "对不起,已经是第一首歌了!", Toast.LENGTH_SHORT).show();
listposition=0;
}
}
});
button_play = (ImageButton) findViewById(R.id.play);
button_play.setOnClickListener(new View.OnClickListener() {//播放歌曲
@Override
public void onClick(View v) {
if (isFirstClick) {//第一次点击播放,默认播放第一首歌
button_play.setBackgroundResource(R.drawable.pause);
Intent intent = new Intent(getApplicationContext(), MusicService.class);
intent.putExtra(Config.TYPE, Config.START_MUSIC);
intent.putExtra(Config.PATH, files[0].getAbsolutePath());
startService(intent);
isFirstClick = false;
isPlay = true;
isPause = false;
} else {
if (isPlay) {
button_play.setBackgroundResource(R.drawable.play);
Intent intent = new Intent(getApplicationContext(), MusicService.class);
intent.putExtra(Config.TYPE, Config.PAUSE_MUSIC);
startService(intent);
isPlay = false;
isPause = true;
} else if (isPause) {
button_play.setBackgroundResource(R.drawable.pause);
Intent intent = new Intent(getApplicationContext(), MusicService.class);
intent.putExtra(Config.TYPE, Config.PAUSE_MUSIC);
startService(intent);
isPlay = true;
isPause = false;
}
}
}
});
ImageButton button_next = (ImageButton) findViewById(R.id.next);
button_next.setOnClickListener(new View.OnClickListener() {//播放下一首歌
@Override
public void onClick(View v) {
button_play.setBackgroundResource(R.drawable.pause);
isFirstClick=false;
isPlay = true;
isPause = false;
listposition=listposition+1;
if(listposition<=files.length-1){
Intent intent = new Intent(getApplicationContext(), MusicService.class);
intent.putExtra(Config.TYPE, Config.START_MUSIC);
intent.putExtra(Config.PATH, files[listposition].getAbsolutePath());
startService(intent);
}else{
Toast.makeText(getApplicationContext(), "对不起,已经是最后一首歌了!", Toast.LENGTH_SHORT).show();
listposition=files.length-1;
}
}
});
}
class MyMusicBroadcastReceicer extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
int type = intent.getIntExtra(Config.TYPE, 0);
SimpleDateFormat format = new SimpleDateFormat("mm:ss");//设置歌曲显示时间格式
switch (type) {
case Config.TOTAL_TIME:
int totalTime = intent.getIntExtra(Config.TIME, 0);
seekBar.setMax(totalTime);
textView_totaltime.setText(format.format(totalTime));
break;
case Config.CURRENT_TIME:
int currentTime = intent.getIntExtra(Config.TIME, 0);
seekBar.setProgress(currentTime);
textView_currenttime.setText(format.format(currentTime));
break;
default:
break;
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(myMusicBroadcastReceicer);//将广播解除注册
}
}