前言
这阵子都在做android相关的开发。写了一个基于MediaPlayer类的MusicPlay——音乐播放 器。因为Demo很简单所 以把什么代码都写在了Activity下,相当严重的坏代码味道(-_-||)。程序实现了歌曲的播放、暂停、停止、上下首、进度条控制、歌曲列表这些功 能,Demo是基于android 2.2版本的。这里把一些关键代码列举出,分析一下。
歌曲列表
我很穷 没有android手机(公司也不给我们配一台~~),全都是用模拟器进行调试的。开发前需要新建一个带SD卡的模拟器,然后把歌曲 添加到模拟器中。在添加歌曲时遇到一个问题,不管我是用命令行添加,还是使用File Explorer,把歌曲PUSH到模拟器的SD卡里。当我再次读出歌曲名称时都遇到了中文乱码,研究发现存储在模拟器上歌曲名称本身就已经是乱码了,问 题出现在PUSH方式上。后来在网上找到了一个解决方法,因为模拟器的SD卡是 img格式的镜像文件,于是我用UltraISO打开,把歌曲放进去再保存成Img文件,中文名乱码问题就解决了。
用一个ListView来显示歌曲列表,使用 ArrayAdapter<String> adapter 简单的将歌曲绑定到ListView上。从SD卡上获取文件我们需要新建一个文件过滤器类,这个类需要实现FilenameFilter接口。
1
//
文件过滤器
2 class MusicFilter implements FilenameFilter {
3
4 @Override
5 public boolean accept(File dir, String filename) {
6
7 return (filename.endsWith( " .mp3 " ));
8 }
9
10 }
2 class MusicFilter implements FilenameFilter {
3
4 @Override
5 public boolean accept(File dir, String filename) {
6
7 return (filename.endsWith( " .mp3 " ));
8 }
9
10 }
获取歌曲列表
1
/**
2 * 播放列表
3 */
4 public void MusicList() {
5 try {
6 File home = new File(PATH);
7
8 File[] f = home.listFiles( new MusicFilter());
9 if (f.length > 0 ) {
10 for ( int i = 0 ; i < f.length; i ++ )
11 {
12
13 File file = f[i];
14 byte [] bytes = file.getName().getBytes( " GB2312 " );
15 String name = new String(bytes, " GB2312 " );
16 musicList.add(name);
17 }
18 ArrayAdapter < String > adapter = new ArrayAdapter < String > ( this ,
19 android.R.layout.simple_list_item_single_choice, musicList);
20 songList.setAdapter(adapter);
21 }
22 }
23 catch (Exception ex)
24 {
25 Toast.makeText( this , " 显示音乐列表异常: " + ex.getMessage(), Toast.LENGTH_LONG).show();
26 }
27
28 }
2 * 播放列表
3 */
4 public void MusicList() {
5 try {
6 File home = new File(PATH);
7
8 File[] f = home.listFiles( new MusicFilter());
9 if (f.length > 0 ) {
10 for ( int i = 0 ; i < f.length; i ++ )
11 {
12
13 File file = f[i];
14 byte [] bytes = file.getName().getBytes( " GB2312 " );
15 String name = new String(bytes, " GB2312 " );
16 musicList.add(name);
17 }
18 ArrayAdapter < String > adapter = new ArrayAdapter < String > ( this ,
19 android.R.layout.simple_list_item_single_choice, musicList);
20 songList.setAdapter(adapter);
21 }
22 }
23 catch (Exception ex)
24 {
25 Toast.makeText( this , " 显示音乐列表异常: " + ex.getMessage(), Toast.LENGTH_LONG).show();
26 }
27
28 }
还需要为歌曲列表添加点击是的响应处理,点击某些Item时将播放该歌曲
@Override
public void onItemClick(AdapterView <?> arg0, View arg1, int arg2, long arg3) {
// TODO Auto-generated method stub
currentSong = arg2;
playMusic(PATH + musicList.get(currentSong));
}
public void onItemClick(AdapterView <?> arg0, View arg1, int arg2, long arg3) {
// TODO Auto-generated method stub
currentSong = arg2;
playMusic(PATH + musicList.get(currentSong));
}
歌曲播放
使用MediaPlayer对歌曲播放进行控制。需要注意的是对播放状态的控制。
public
void
playMusic(String path) {
try
{
if (isPlaying)
{
player.stop();
}
player.reset();
player.setDataSource(path);
player.prepare();
player.start();
isPlaying = true ;
isPause = false ;
isStop = false ;
// 设置进度条
barCount = player.getDuration();
bar.setMax(barCount); // 设置最大值.
String time = formatTime(barCount);
txtTotalTime.setText(time);
txtPlaying.setText( " 当前播放歌曲: " + this .musicList.get( this .currentSong));
btnPlay .setImageResource(R.drawable.pause);
songList.setItemChecked(currentSong, true );
}
catch (IOException e)
{
// TODO Auto-generated catch block
Log.v(getString(R.string.app_name), e.getMessage());
}
}
try
{
if (isPlaying)
{
player.stop();
}
player.reset();
player.setDataSource(path);
player.prepare();
player.start();
isPlaying = true ;
isPause = false ;
isStop = false ;
// 设置进度条
barCount = player.getDuration();
bar.setMax(barCount); // 设置最大值.
String time = formatTime(barCount);
txtTotalTime.setText(time);
txtPlaying.setText( " 当前播放歌曲: " + this .musicList.get( this .currentSong));
btnPlay .setImageResource(R.drawable.pause);
songList.setItemChecked(currentSong, true );
}
catch (IOException e)
{
// TODO Auto-generated catch block
Log.v(getString(R.string.app_name), e.getMessage());
}
}
暂停、停止、完成播放
这几个操作比较简单,主要是调用MediaPlayer的对应方法,然注意修改View的状态(这里应该将View状态修改提取出来的,有写职责混乱)
protected
void
pause() {
if (player.isPlaying()) {
player.stop(); // 停止
this .btnPlay .setImageResource(R.drawable.play);
this .txtPlaying.setText( " 暂停播放歌曲: " + this .musicList.get( this .currentSong));
this .isPause = true ;
this .isPlaying = false ;
this .isStop = false ;
}
}
if (player.isPlaying()) {
player.stop(); // 停止
this .btnPlay .setImageResource(R.drawable.play);
this .txtPlaying.setText( " 暂停播放歌曲: " + this .musicList.get( this .currentSong));
this .isPause = true ;
this .isPlaying = false ;
this .isStop = false ;
}
}
public
void
stopMusic() {
this .isPlaying = false ;
this .isStop = true ;
this .isPause = false ;
this .btnPlay .setImageResource(R.drawable.play);
this .txtPlaying.setText( " 停止播放 " );
if (player.isPlaying())
{
player.stop(); // 停止
}
}
this .isPlaying = false ;
this .isStop = true ;
this .isPause = false ;
this .btnPlay .setImageResource(R.drawable.play);
this .txtPlaying.setText( " 停止播放 " );
if (player.isPlaying())
{
player.stop(); // 停止
}
}
需要监听播放完一首歌曲后应当播放下一首,这里需要监听播放完成事件 player.setOnCompletionListener(this);
@Override
public void onCompletion(MediaPlayer arg0) {
// TODO Auto-generated method stub
try
{
nextMusic();
}
catch (Exception e)
{
txtPlaying.setText(e.toString());
e.printStackTrace();
}
}
public void onCompletion(MediaPlayer arg0) {
// TODO Auto-generated method stub
try
{
nextMusic();
}
catch (Exception e)
{
txtPlaying.setText(e.toString());
e.printStackTrace();
}
}
上一首、下一首播放
代码比较简单就直接贴出来了
public
void
nextMusic() {
int num = this .musicList.size();
if ( ++ this .currentSong >= num) {
currentSong = 0 ;
}
stopMusic();
playMusic(PATH + musicList.get(currentSong));
}
int num = this .musicList.size();
if ( ++ this .currentSong >= num) {
currentSong = 0 ;
}
stopMusic();
playMusic(PATH + musicList.get(currentSong));
}
public
void
lastMusic() {
int num = musicList.size();
if ( -- currentSong < 0 ) {
currentSong = num - 1 ;
}
stopMusic();
playMusic(PATH + musicList.get(currentSong));
}
int num = musicList.size();
if ( -- currentSong < 0 ) {
currentSong = num - 1 ;
}
stopMusic();
playMusic(PATH + musicList.get(currentSong));
}
这些就是对播放的基本控制了。除了这个以外我们还需要对播放错误进行监听 player.setOnErrorListener(this);
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
// TODO Auto-generated method stub
try
{
/* 发生错误时也解除资源与MediaPlayer的赋值 */
mp.release();
mp.reset();
this .txtPlaying.setText( " 播放发生异常! " );
}
catch (Exception e)
{
this .txtPlaying.setText(e.toString());
e.printStackTrace();
}
return false ;
}
public boolean onError(MediaPlayer mp, int what, int extra) {
// TODO Auto-generated method stub
try
{
/* 发生错误时也解除资源与MediaPlayer的赋值 */
mp.release();
mp.reset();
this .txtPlaying.setText( " 播放发生异常! " );
}
catch (Exception e)
{
this .txtPlaying.setText(e.toString());
e.printStackTrace();
}
return false ;
}
进度条
进度条用来显示当前歌曲的播放进度,同时还需要具有拖拽定点播放功能。这里需要使用到线程和消息机制。Demo中我让Activity实现了Runnable接口。
@Override
public void run() {
// TODO Auto-generated method stub
while ( true ) {
try {
int n = player.getCurrentPosition();
Message msg = new Message();
msg.what = n;
handler.sendMessage(msg);
Thread.sleep( 100 );
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
public void run() {
// TODO Auto-generated method stub
while ( true ) {
try {
int n = player.getCurrentPosition();
Message msg = new Message();
msg.what = n;
handler.sendMessage(msg);
Thread.sleep( 100 );
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
消息处理代码
public
Handler handler
=
new
Handler() {
public void handleMessage(Message msg) {
super .handleMessage(msg);
bar.setProgress(msg.what);
currentBar = msg.what;
if (isPlaying)
{
String time = formatTime(msg.what);
txtNowTime.setText(time);
}
bar.invalidate();
}
};
public void handleMessage(Message msg) {
super .handleMessage(msg);
bar.setProgress(msg.what);
currentBar = msg.what;
if (isPlaying)
{
String time = formatTime(msg.what);
txtNowTime.setText(time);
}
bar.invalidate();
}
};
拖动进度条是的定点播放
bar.setOnSeekBarChangeListener(
new
OnSeekBarChangeListener() {
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
bar.setProgress(currentBar);
player.seekTo(currentBar);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
// TODO Auto-generated method stub
currentBar = progress;
}
});
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
bar.setProgress(currentBar);
player.seekTo(currentBar);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
// TODO Auto-generated method stub
currentBar = progress;
}
});
小结
MusicPlay的各项功能主要是通过对MediaPlayer类的调用实现的。程序中具有较重的“代码坏味道”,等有空需要整理整理。
【转载】http://www.cnblogs.com/keyindex/archive/2010/08/20/Musicplay-android.html