MainActivity 代码

package cn.tedu.music_player_2.activity;

import java.util.List;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.SeekBar;
import android.widget.TextView;
import cn.tedu.music_player_2.R;
import cn.tedu.music_player_2.adapter.MusicAdapter;
import cn.tedu.music_player_2.app.MusicPlayerApplication;
import cn.tedu.music_player_2.entity.Music;
import cn.tedu.music_player_2.service.PlayMusicService;
import cn.tedu.music_player_2.util.CommonUtils;
import cn.tedu.music_player_2.util.IMusicPlayer;

/**
* MainActivity
*
* @author chengheng
* @version 2.0
*/
public class MainActivity extends Activity implements View.OnClickListener,

OnItemClickListener, OnSeekBarChangeListener {
/**
* ListView:歌曲列表
*/
private ListView lvMusics;
/**
* ImageButton:播放或暂停
*/
private ImageButton ibPlayOrPause;
/**
* ImageButton:播放上一首
*/
private ImageButton ibPrevious;
/**
* ImageButton:播放下一首
*/
private ImageButton ibNext;
/**
* TextView:显示当前播放的歌曲的名称
*/
private TextView tvMusicTitle;
/**
* SeekBar:歌曲的播放进度
*/
private SeekBar sbMusicProgress;
/**
* TextView:歌曲当前播放到的时间
*/
private TextView tvMusicCurrentPosition;
/**
* TextView:当前播放的歌曲的时长
*/
private TextView tvMusicDuration;
/**
* 歌曲数据的List集合
*/
private List musics;
/**
* 歌曲列表的Adapter
*/
private MusicAdapter musicAdapter;
/**
* Application
*/
private MusicPlayerApplication app;
/**
* ServiceConnection:Activity与Service建立的连接
*/
private InnerServiceConnection conn;
/**
* 当Activity与Service连接后,调用Service方法的工具
*/
private IMusicPlayer player;
/**
* 更新歌曲播放信息的线程
*/
private UpdateProgressThread updateProgressThread;
/**
* 播放器是否已经开始运行
*/
private boolean isPlayerWorking;
/**
* 用户是否正在拖拽进度条
*/
private boolean isUserTrackingTouch;

@Overrideprotected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_main);    // 绑定Service    Intent intent = new Intent(this, PlayMusicService.class);    conn = new InnerServiceConnection();    bindService(intent, conn, BIND_AUTO_CREATE);    // 初始化控件    lvMusics = (ListView) findViewById(R.id.lv_musics);    ibPlayOrPause = (ImageButton) findViewById

(R.id.ib_play_or_pause);
ibPrevious = (ImageButton) findViewById(R.id.ib_previous);
ibNext = (ImageButton) findViewById(R.id.ib_next);
tvMusicTitle = (TextView) findViewById(R.id.tv_music_title);
sbMusicProgress = (SeekBar) findViewById(R.id.sb_music_progress);
tvMusicCurrentPosition = (TextView) findViewById

(R.id.tv_music_current_position);
tvMusicDuration = (TextView) findViewById

(R.id.tv_music_duration);

    // 获取歌曲列表的数据    app = (MusicPlayerApplication) getApplication();    musics = app.getMusics();    // 显示歌曲列表的ListView    musicAdapter = new MusicAdapter(this, musics);    lvMusics.setAdapter(musicAdapter);    // 为按钮配置监听器    ibPlayOrPause.setOnClickListener(this);    ibPrevious.setOnClickListener(this);    ibNext.setOnClickListener(this);    // 为ListView配置监听器    lvMusics.setOnItemClickListener(this);    // 为SeekBar配置监听器    sbMusicProgress.setOnSeekBarChangeListener(this);}@Overrideprotected void onRestart() {    // 判断是否正在播放    if(player.callIsPlaying()) {        // 开启线程更新播放信息        startUpdateProgressThread();    }    super.onRestart();}@Overrideprotected void onStop() {    // 停止更新播放信息    stopUpdateProgressThread();    super.onStop();}@Overrideprotected void onDestroy() {    // 解除与Service的绑定    if (conn != null) {        unbindService(conn);    }    super.onDestroy();}@Overridepublic void onClick(View v) {    switch (v.getId()) {    case R.id.ib_play_or_pause:        // 判断当前的状态        if (player.callIsPlaying()) {            // 正在播放,则暂停            player.callPause();            // 更换按钮图片:换为“播放”            ibPlayOrPause.setImageResource

(android.R.drawable.ic_media_play);
// 停止更新歌曲播放信息
stopUpdateProgressThread();
} else {
// 没有播放,则播放
player.callPlay();
// 更换按钮图片:换为“暂停”
ibPlayOrPause.setImageResource

(android.R.drawable.ic_media_pause);
// 开启线程,更新播放信息
startUpdateProgressThread();
// 更新标识:播放器开始工作
isPlayerWorking = true;
}
break;

    case R.id.ib_previous:        // 播放上一首        player.callPrevious();        // 更换按钮图片:换为“暂停”        ibPlayOrPause.setImageResource

(android.R.drawable.ic_media_pause);
// 开启线程,更新播放信息
startUpdateProgressThread();
// 更新标识:播放器开始工作
isPlayerWorking = true;
break;

    case R.id.ib_next:        // 播放下一首        player.callNext();        // 更换按钮图片:换为“暂停”        ibPlayOrPause.setImageResource

(android.R.drawable.ic_media_pause);
// 开启线程,更新播放信息
startUpdateProgressThread();
// 更新标识:播放器开始工作
isPlayerWorking = true;
break;
}
}

@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position, 

long id) {
// 播放指定的歌曲
player.callPlay(position);
// 更换按钮图片:换为“暂停”
ibPlayOrPause.setImageResource

(android.R.drawable.ic_media_pause);
// 开启线程,更新播放信息
startUpdateProgressThread();
// 更新标识:播放器开始工作
isPlayerWorking = true;
}

@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {    // 标志用户正在拖拽进度条    isUserTrackingTouch = true;}@Overridepublic void onStopTrackingTouch(SeekBar seekBar) {    // 标志用户已经停止拖拽进度条    isUserTrackingTouch = false;    // 判断播放器是否已开始工作    if(isPlayerWorking) {        // 获取拖拽后的进度        int progress = sbMusicProgress.getProgress();        // 调用Service中对应的方法        player.callSeekTo(progress);        // 开启线程,更新播放进度        startUpdateProgressThread();        // 设置播放按钮显示的图片为“暂停”        ibPlayOrPause.setImageResource

(android.R.drawable.ic_media_pause);
}
}

/** * 开启线程,更新播放信息 */private void startUpdateProgressThread() {    if(updateProgressThread == null) {        updateProgressThread = new UpdateProgressThread();        updateProgressThread.setRunning(true);        updateProgressThread.start();    }}/** * 停止更新播放信息的线程 */private void stopUpdateProgressThread() {    if(updateProgressThread != null) {        updateProgressThread.setRunning(false);        updateProgressThread = null;    }}/** * 更新播放信息的线程 */private class UpdateProgressThread extends Thread {    private boolean isRunning;    private String musicName;    private int progress;    private String currentPositionString;    private String durationString;    public void setRunning(boolean isRunning) {        this.isRunning = isRunning;    }    private Runnable runner = new Runnable() {        @Override        public void run() {            // 更新控件:歌曲标题            tvMusicTitle.setText(musicName);            // 更新控件:当前歌曲时长            tvMusicDuration.setText(durationString);            // 更新控件:当前播放时间            tvMusicCurrentPosition.setText

(currentPositionString);

            // 判断用户是否正在拖拽进度条            if(!isUserTrackingTouch) {                // 更新控件:进度条                sbMusicProgress.setProgress(progress);            }        }    };    @Override    public void run() {        // 循环        while(isRunning) {            // 日志            Log.d("tedu", "UpdateProgressThread.run()");            // 判断是否正在播放            if(player.callIsPlaying()) {                // 获取所需的数据                int currentMusicIndex = 

player.callGetCurrentMusicIndex();
int currentPosition =

player.callGetCurrentPosition();
int duration = player.callGetDuration();

                // 计算需要被显示的数据                musicName = "正在播放:" + musics.get

(currentMusicIndex).getName();
progress = currentPosition * 100 /

duration;
currentPositionString =

CommonUtils.getFormattedTime(currentPosition);
durationString =

CommonUtils.getFormattedTime(duration);

                // 更新显示                runOnUiThread(runner);            }            // 休眠            try {                Thread.sleep(500);            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }}/** * ServiceConnection */private class InnerServiceConnection implements ServiceConnection {    @Override    public void onServiceConnected(ComponentName name, IBinder 

service) {
player = (IMusicPlayer) service;
}

    @Override    public void onServiceDisconnected(ComponentName name) {        // (无视)    }}@Overridepublic void onProgressChanged(SeekBar seekBar, int progress, boolean 

fromUser) {
// (无视)
}

}

MusicAdapter 代码

package cn.tedu.music_player_2.adapter;

import java.util.List;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import cn.tedu.music_player_2.R;
import cn.tedu.music_player_2.R.id;
import cn.tedu.music_player_2.R.layout;
import cn.tedu.music_player_2.entity.Music;

/**
* 显示歌曲列表ListView的Adapter
* @author chengheng
* @version 2.0
*/
public class MusicAdapter extends BaseAdapter {
/**
* Context
*/
private Context context;
/**
* 歌曲列表的数据
*/
private List musics;

/** * 构造方法 * @param context 上下文对象 * @param musics 歌曲的数据的List集合 */public MusicAdapter(Context context, List<Music> musics) {    super();    this.context = context;    this.musics = musics;}@Overridepublic int getCount() {    return musics.size();}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {    Music music = musics.get(position);    if (convertView == null) {        LayoutInflater inflater = LayoutInflater.from(context);        convertView = inflater.inflate(R.layout.music_item, null);    }    TextView tvName = (TextView) convertView.findViewById(R.id.tv_music_item_name);    TextView tvPath = (TextView) convertView.findViewById(R.id.tv_music_item_path);    tvName.setText(music.getName());    tvPath.setText(music.getPath());    return convertView;}@Overridepublic Object getItem(int position) {    return null;}@Overridepublic long getItemId(int position) {    return 0;}

}

自定义的application代码

package cn.tedu.music_player_2.app;

import java.util.List;

import android.app.Application;
import android.util.Log;
import cn.tedu.music_player_2.dal.IDao;
import cn.tedu.music_player_2.dal.MusicDaoFactory;
import cn.tedu.music_player_2.entity.Music;

public class MusicPlayerApplication extends Application {
private List musics = null;

@Overridepublic void onCreate() {    // 日志    Log.e("tedu", "MusicPlayerApplication.onCreate()");    // 获取数据    Log.e("tedu", "MusicPlayerApplication. 准备获取歌曲列表!");    // MusicDao dao = new MusicDao();    IDao dao = MusicDaoFactory.newInstance();    musics = dao.getData();    Log.e("tedu", "MusicPlayerApplication. 获取歌曲列表完成!");}/** * 获取歌曲数据的List集合 * @return 歌曲数据的List集合,该返回值永不为null */public List<Music> getMusics() {    return musics;}

}

工具类IDao代码:

package cn.tedu.music_player_2.dal;

import java.util.List;

import cn.tedu.music_player_2.entity.Music;

public interface IDao {

List<Music> getData();

}

工具类InternetMusicDao 代码:

package cn.tedu.music_player_2.dal;

import java.util.ArrayList;
import java.util.List;

import cn.tedu.music_player_2.entity.Music;

public class InternetMusicDao implements IDao {

@Overridepublic List<Music> getData() {    List<Music> musics = new ArrayList<Music>();    Music m1 = new Music();    m1.setName("长城");    m1.setPath("http://mp3.baidu.com/changcheng.mp3");    musics.add(m1);    Music m2 = new Music();    m2.setName("大地");    m2.setPath("http://mp3.baidu.com/dadi.mp3");    musics.add(m2);    Music m3 = new Music();    m3.setName("光辉岁月");    m3.setPath("http://mp3.baidu.com/guanghuisuiyue.mp3");    musics.add(m3);    return musics;}

}

LoadMusicDao 代码;

package cn.tedu.music_player_2.dal;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import android.os.Environment;
import android.util.Log;
import cn.tedu.music_player_2.entity.Music;

/**
* 歌曲数据的访问类
* @author chengheng
* @version 2.0
*/
public class LocalMusicDao implements IDao {
/**
* 扫描sdcard中Music下所有.mp3文件
* @return 扫描到的Music对象的List集合,该返回值永不为null
*/
@Override
public List getData() {
// 准备返回值
List musics = new ArrayList();

    // 扫描sdcard中Music下所有.mp3文件    if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {        File dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC);        if (dir.exists()) {            File[] files = dir.listFiles();            if (files != null && files.length > 0) {                for (int i = 0; i < files.length; i++) {                    if (files[i].isFile()) {                        if (files[i].getName().toLowerCase(Locale.CHINA).endsWith(".mp3")) {                            Music music = new Music();                            music.setPath(files[i].getAbsolutePath());                            music.setName(files[i].getName().substring(0, files[i].getName().length() - 4));                            Log.v("tedu", "" + music);                            musics.add(music);                        }                    }                }            } else {                Log.w("tedu", "Music文件夹下没有有效的文件!");            }        } else {            Log.w("tedu", "sdcard下Music文件夹不存在!无法扫描到歌曲!");        }    } else {        Log.w("tedu", "sdcard没有正确挂载!无法访问!");    }    // 返回    return musics;}

}

工具类MusicDaoFactory 代码;

package cn.tedu.music_player_2.dal;

public class MusicDaoFactory {
private MusicDaoFactory() {

}public static IDao newInstance() {    return new LocalMusicDao();}

}

实体类 Music 代码

package cn.tedu.music_player_2.entity;

/**
* 歌曲信息的实体类
* @author chengheng
* @version 2.0
*/
public class Music {
/**
* 歌曲名称,用于显示
*/
private String name;
/**
* 歌曲路径
*/
private String path;

public String getName() {    return name;}public void setName(String name) {    this.name = name;}public String getPath() {    return path;}public void setPath(String path) {    this.path = path;}@Overridepublic String toString() {    return "Music [name=" + name + ", path=" + path + "]";}

}

service服务PlayMusicSevice

package cn.tedu.music_player_2.service;

import java.io.IOException;
import java.util.List;

import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Binder;
import android.os.IBinder;
import cn.tedu.music_player_2.app.MusicPlayerApplication;
import cn.tedu.music_player_2.entity.Music;
import cn.tedu.music_player_2.util.IMusicPlayer;

public class PlayMusicService extends Service {
/**
* 播放工具
*/
private MediaPlayer player;
/**
* 歌曲数据的List集合
*/
private List musics;
/**
* Application
*/
private MusicPlayerApplication app;
/**
* 当前播放的歌曲的索引
*/
private int currentMusicIndex;
/**
* 暂停位置
*/
private int pausePosition;

@Overridepublic void onCreate() {    // 创建MediaPlayer    player = new MediaPlayer();    // 获取歌曲列表的数据    app = (MusicPlayerApplication) getApplication();    musics = app.getMusics();    // 为MediaPlayer对象配置监听器    player.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {        @Override        public void onCompletion(MediaPlayer mp) {            // 播放下一首            next();        }    });    player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {        @Override        public void onPrepared(MediaPlayer mp) {            // 快进到之前暂停的位置            player.seekTo(pausePosition);            // 播放            player.start();        }    });}@Overridepublic IBinder onBind(Intent intent) {    InnerBinder binder = new InnerBinder();    return binder;}@Overridepublic void onDestroy() {    // 释放播放器相关资源    player.release();    player = null;}/** * Binder */private class InnerBinder extends Binder implements IMusicPlayer {    @Override    public void callPlay() {        PlayMusicService.this.play();    }    @Override    public void callPause() {        PlayMusicService.this.pause();    }    @Override    public void callPrevious() {        PlayMusicService.this.previous();    }    @Override    public void callNext() {        PlayMusicService.this.next();    }    @Override    public boolean callIsPlaying() {        return player.isPlaying();    }    @Override    public void callPlay(int position) {        PlayMusicService.this.play(position);    }    @Override    public int callGetCurrentMusicIndex() {        return currentMusicIndex;    }    @Override    public int callGetCurrentPosition() {        return player.getCurrentPosition();    }    @Override    public int callGetDuration() {        return player.getDuration();    }    @Override    public void callSeekTo(int progress) {        PlayMusicService.this.seekTo(progress);    }}/** * 播放 */private void play() {    try {        // 1. 重置        player.reset();        // 2. 设置歌曲的路径        player.setDataSource(musics.get(currentMusicIndex).getPath());        // 3. 异步加载歌曲数据,必须匹配OnPreparedListener        player.prepareAsync();

// // 3. 加载歌曲数据
// player.prepare();
// // 4. 快进到暂停位置
// player.seekTo(pausePosition);
// // 5. 播放
// player.start();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

/** * 播放指定的歌曲 *  * @param position *            歌曲的索引 */private void play(int position) {    // 确定需要播放的歌曲的索引    currentMusicIndex = position;    // 清除暂停位置    pausePosition = 0;    // 播放    play();}/** * 暂停 */private void pause() {    // 暂停播放    player.pause();    // 记录当前播放到的位置    pausePosition = player.getCurrentPosition();}/** * 播放上一首 */private void previous() {    // 计算上一首歌曲的索引值    currentMusicIndex--;    if (currentMusicIndex < 0) {        currentMusicIndex = musics.size() - 1;    }    // 清除暂停位置    pausePosition = 0;    // 播放    play();}/** * 播放下一首 */private void next() {    // 计算上一首歌曲的索引值    currentMusicIndex++;    if (currentMusicIndex >= musics.size()) {        currentMusicIndex = 0;    }    // 清除暂停位置    pausePosition = 0;    // 播放    play();}/** * 快进到指定的进度位置开始播放 *  * @param progress *            进度值,假设从60%位置开始播放,则参数值为60 */private void seekTo(int progress) {    // 根据进度计算出需要从??毫秒开始播放,并将值赋给pausePosition    pausePosition = player.getDuration() * progress / 100;    // 播放    play();}

}

commonutils 类代码:

package cn.tedu.music_player_2.util;

import java.util.Date;
import java.text.SimpleDateFormat;
import java.util.Locale;
/**
* 通用工具类
*/
public class CommonUtils {
/**
* 格式化时间的工具
*/
private static SimpleDateFormat sdf = new SimpleDateFormat(“mm:ss”, Locale.CHINA);
/**
* 被格式化的时间对象
*/
private static Date date = new Date();

/** * 获取格式化后的时间 *  * @param timeMillis *            时间值,取值为从1970-1-1 0:00:00至今的毫秒数 * @return 格式化为mm:ss格式的字符串 */public static String getFormattedTime(long timeMillis) {    // 设置时间    date.setTime(timeMillis);    // 返回格式化后的结果    return sdf.format(date);}

}

consts工具类

package cn.tedu.music_player_2.util;

/**
* 保存常量
* @author chengheng
* @version 2.0
*/
public interface Consts {
/**
* 指令:播放或暂停
*/
int COMMAND_PLAY_OR_PAUSE = 0;
/**
* 指令:播放上一首
*/
int COMMAND_PREVIOUS = 1;
/**
* 指令:播放下一首
*/
int COMMAND_NEXT = 2;
/**
* 指令:播放指定的歌曲
*/
int COMMAND_PLAY_POSITION = 3;

/** * Intent中封装的数据的key:指令 */String EXTRA_COMMAND = "command";/*** Intent中封装的数据的key:需要播放的歌曲的索引*/String EXTRA_POSITION = "position";

}

IMusicPlayer类代码:

package cn.tedu.music_player_2.util;

public interface IMusicPlayer {
/**
* 播放歌曲
*/
void callPlay();

/** * 暂停播放 */void callPause();/** * 播放上一首 */void callPrevious();/** * 播放下一首 */void callNext();/** * 获取播放状态,即判断是否正在播放 *  * @return 返回true则表示正在播放,返回false则表示没有播放 */boolean callIsPlaying();/** * 播放指定的歌曲 *  * @param position *            歌曲的索引 */void callPlay(int position);/** * 获取当前播放的歌曲的索引 *  * @return 当前播放的歌曲的索引 */int callGetCurrentMusicIndex();/** * 获取当前播放到的位置 *  * @return 当前播放到的位置 */int callGetCurrentPosition();/** * 获取当前播放的歌曲的时长 *  * @return 当前播放的歌曲的时长 */int callGetDuration();/** * 快进到指定的进度位置开始播放 *  * @param progress *            进度值,假设从60%位置开始播放,则参数值为60 */void callSeekTo(int progress);

}

更多相关文章

  1. Android 读取网络数据
  2. Android 线程同步 ConditionVariable的用法
  3. Android中数据库升级
  4. android直接读取数据库文件
  5. android listview无限循环显示数据
  6. FFmpeg In Android - tutorial-4-Spawning Threads创建线程
  7. android 加密数据库
  8. Android学习笔记(6)————Android的线程与进程
  9. android 数据库

随机推荐

  1. Android 发版的小工具
  2. 详解android之activity的生命周期
  3. android之menu相关
  4. Android中记录与调试——Logcat和Debug的
  5. Android通用布局对象
  6. 为什么微软可以向安卓厂商收取专利费
  7. android project 编译过程
  8. Android上最好的第三方浏览器有哪些不错
  9. Android窗口机制之由setContentView引发
  10. Android源码编译第三方app(Android studi