sd卡本地音乐播放器
程序员文章站
2022-07-10 18:55:20
为了更好的android的内容进行综合使用作,以及提供给更入门Android做为一个领路的文章,简单的制作了一个音乐播放器,实现简单的拖动进度条实现快进退功能以及其他的上一曲、下一曲、开始/暂停、 停止简单、播放模式等功能,用到了listview、SQLite、seekbar,button等常见组件。实现的结果如图所示:显示并播放music文件夹内的600多首mp3音乐。......
为了更好的对所学的android的内容进行综合使用,简单的制作了一个音乐播放器,实现简单的拖动进度条实现快进退功能以及其他的上一曲、下一曲、开始/暂停、 停止简单、播放模式等功能,用到了listview、SQLite、seekbar,button等常见组件。实现的结果如图所示:显示并播放music文件夹内的600多首mp3音乐。
一、歌曲信息的存储----SQLIite数据库
由于歌曲数目太多,为了避免每次启动软件都需要扫描目录并形成列表,所以只通过按钮扫描目录并把信息存储到数据库中。以后只需要读取数据库的就可以了。花费时间大大缩减。
public class DBUtils extends SQLiteOpenHelper {
static SQLiteDatabase db;
public DBUtils( Context context ) {
super(context, "Music", null, 1);
this.db=this.getWritableDatabase();
}
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
String sql="create table song(id integer primary key autoincrement,title text,path text )";
sqLiteDatabase.execSQL(sql);
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
}
//扫描music把歌曲信息添加到数据库
public static void AddSong(File sdpath){
List<SongBean> songBeanList=new ArrayList<SongBean>();
File path=new File(sdpath.toString()+ File.separator+"Music");
for (int i=0;i<path.listFiles().length;i++){//遍历path目录里的文件
File childFile=path.listFiles()[i];
if (childFile.toString().endsWith(".mp3")){
ContentValues values=new ContentValues();
values.put("title",childFile.getName());
values.put("path",childFile.getAbsolutePath());
db.insert("song",null,values);
}
}
}
//查询歌曲信息
public static List<SongBean> QueryAll(){
Cursor cursor=db.query("song",null,null,null,null,null,null);
List<SongBean> songBeanList=new ArrayList<SongBean>();
if (cursor!=null){
while (cursor.moveToNext()){
SongBean songBean=new SongBean();
songBean.setTitle(cursor.getString(cursor.getColumnIndex("title")));
songBean.setPath(cursor.getString(cursor.getColumnIndex("path")));
songBeanList.add(songBean);
}
}
cursor.close();
return songBeanList;
}
}
二、ListView显示歌曲名称,需要继承BaseAdapter
public class MyBaseAdapter extends BaseAdapter {
List<SongBean> songList;
LayoutInflater layoutInflater;
public MyBaseAdapter(List<SongBean> mmList, Context context) {
this.songList = mmList;
this.layoutInflater=LayoutInflater.from(context);
}
@Override
public int getCount() {
return songList==null?0:songList.size();
}
@Override
public Object getItem(int i) {
return songList.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View convertView, ViewGroup viewGroup) {
MyViewHolder myViewHolder=null;
if(convertView==null){
convertView = layoutInflater.inflate(R.layout.song_item, null);
myViewHolder=new MyViewHolder(convertView);
convertView.setTag(myViewHolder);
}else
myViewHolder= (MyViewHolder) convertView.getTag();
SongBean song= (SongBean) getItem(i); myViewHolder.tv_songname.setText(song.getTitle().substring(0,song.getTitle().length()-4));
//myViewHolder.tv_songauthor.setText(song.getPath());
myViewHolder.tv_songauthor.setVisibility(View.INVISIBLE);
return convertView;
}
public static class MyViewHolder {
public View rootView;
public TextView tv_songname;
public TextView tv_songauthor;
public MyViewHolder(View rootView) {
this.rootView = rootView;
this.tv_songname = (TextView) rootView.findViewById(R.id.tv_songnaem);
this.tv_songauthor = (TextView) rootView.findViewById(R.id.tv_songauthor);
}
}
}
三、服务service
播放音乐并更新进度条和时间,用到service在后台执行,并发送消息到队列。
public class MyService extends Service {
private MediaPlayer mp;
private String song_Path;//歌曲名称
public String getSong_Path() {
return song_Path;
}
public void setSong_Path(String song_Path) {
this.song_Path = song_Path;
}
private LocalBinder localBinder=new LocalBinder();
class LocalBinder extends Binder {
public MyService getss(){
return MyService.this;
}
}//返回myservice对象
public int getposition(){//获取播放位置
return mp.getCurrentPosition();
}
public int gettotaltime(){//获取总时间
return mp.getDuration();
}
//获取播放进度百分比
public double getProgress(){
int position=mp.getCurrentPosition();//获取播放位置
int totaltime=mp.getDuration();//获取总时间
double progress=(double)position/(double)totaltime;//计算播放百分比
return progress;
}
//设置播放进度
public void setProgress(int max,int dest){
int totaltime=mp.getDuration();//获取总时间
mp.seekTo(totaltime*dest/max);//定位播放位置,播放
}
//重新播放
public void restart(){
if (mp!=null){
mp.start();
}else
init();
}
//播放
public void start(){
if (mp!=null){
try {
mp.reset();
mp.setDataSource(song_Path);
mp.prepareAsync();
} catch (IOException e) {
e.printStackTrace();
}
mp.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mediaPlayer) {
mp.start();
}
});
}
else
init();
}
//暂停
public void pause(){
if(mp!=null && mp.isPlaying())
mp.pause();
}
//停止
public void stop(){
if (mp!=null && mp.isPlaying()){
mp.stop();
mp.release();
mp=null;
}
}
//初始化,准备播放
public void init(){
mp=new MediaPlayer();
mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
}
@Override
public void onCreate() {
super.onCreate();
init();////初始化,准备播放
}
@Override
public void onDestroy() {
if (mp!=null && mp.isPlaying()){
mp.stop();
mp.release();
mp=null;
}
super.onDestroy();
}
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
@Override
public IBinder onBind(Intent intent) {
return localBinder ;
}
}
四、在主界面的各个控件的对播放进度信息的控制及显示
//声明创建Handler对象,处理线程发送的消息,更新进度条及当前时间和总时长
@SuppressLint("HandlerLeak")
final Handler mHandler=new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case 0:
double progress=msg.getData().getDouble("pro");//获取线程传送的播放进度百分比
int max=seekBar.getMax();//获取进度条的最大值
int position=(int)(max*progress);//计算进度的当前值
seekBar.setProgress(position);//设置进度
if (position==99)
play_next_song();
int duration=msg.getData().getInt("dura");
int posi=msg.getData().getInt("posi");
//歌曲总时长
int minute=duration/1000/60;
int second=duration/1000%60;
String strmin=null;
String strsec=null;
if (minute<10)
strmin="0"+minute;
else
strmin=minute+"";
if (second<10)
strsec="0"+second;
else
strsec=second+"";
tv_totaltime.setText(strmin+":"+strsec);
//歌曲当前播放时长
minute=posi/1000/60;
second=posi/1000%60;
if (minute<10)
strmin="0"+minute;
else
strmin=minute+"";
if (second<10)
strsec="0"+second;
else
strsec=second+"";
tv_currenttime.setText(strmin+":"+strsec);
break;
default:break;
}
}
};
//线程获取播放进度的百分比,并每隔10ms发送一次
Thread mthread=new Thread(new Runnable() {
@Override
public void run() {
//标识是否在播放状态,用来控制线程退出
while(playstatus){//播放或暂停状态,更新进度条为播放进度
try {
if (mbound){//已绑定,才能更新进度条
Message msg=new Message();
Bundle data=new Bundle();
double progress=myService.getProgress();
int posi=myService.getposition();
int dura=myService.gettotaltime();
msg.what=0;
data.clear();//清空bundle对象,再保存值。不可缺少。
data.putDouble("pro",progress);
data.putInt("posi",posi);
data.putInt("dura",dura);
msg.setData(data);
mHandler.sendMessage(msg);
}
Thread.sleep(10);//休眠
}catch (Exception e){
e.printStackTrace();
}
}
}
});
列表项的单击事件
songlist.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
playstatus=false;
myService.stop();
currentindex=i;
myService.setSong_Path(songBeanList.get(i).getPath());
myService.init();
myService.start();
tv_currentname.setText(songBeanList.get(currentindex).getTitle());
songlist.smoothScrollToPosition(currentindex);
songlist.setSelection(currentindex);
playstatus=true;
mthread.start();
}
});
//拖动滚动条时,更新播放进度
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
//手动调节进度
int dest=seekBar.getProgress();
int max=seekBar.getMax();
myService.setProgress(max,dest); }
});
各个按钮的点击事件
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.play://单击播放按钮
if (mbound )//已绑定
if (!playstatus){//停止后,重新播放
myService.init();
myService.setSong_Path(songBeanList.get(currentindex).getPath());
myService.start();
playstatus=true;
}else{//暂停后,继续播放
myService.restart();
playstatus=true;
}
tv_currentname.setText(songBeanList.get(currentindex).getTitle());
songlist.smoothScrollToPosition(currentindex);
songlist.setSelection(currentindex);
//停止播放后,线程已销毁,需要重新开启线程
mthread.start();
break;
case R.id.pause://单击暂停按钮
if (mbound)
myService.pause();//暂停
playstatus=true;//线程继续执行更新界面,不销毁
break;//
case R.id.stop:
if (mbound)
playstatus=false;//线程销毁,不更新界面
seekBar.setProgress(0);//进度条归0
tv_currenttime.setText("00:00");
myService.stop();//停止播放
break;
case R.id.next_song://下一首歌曲根据播放模式确定
play_next_song();
break;
case R.id.chooseMode:
if (mode==1){
mode=0;
btn_choosemode.setText("顺序播放");
Toast.makeText(MainActivity.this,"当前为随机播放模式!",Toast.LENGTH_SHORT).show();
}else{
mode=1;
btn_choosemode.setText("随机播放");
Toast.makeText(MainActivity.this,"当前为顺序播放模式!",Toast.LENGTH_SHORT).show();
}
break;
case R.id.loadMusic:
Toast.makeText(MainActivity.this,"请稍后,正在本地扫描歌曲。。。。。",Toast.LENGTH_LONG).show();
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
DBUtils.AddSong(Environment.getExternalStorageDirectory());
}
songBeanList=DBUtils.QueryAll();
myBaseAdapter.notifyDataSetChanged();
break;
}
}
////下一首歌曲根据播放模式确定
public void play_next_song() {
playstatus=false;
myService.stop();
if (mode==1){//顺序播放
currentindex++;
if (currentindex<songBeanList.size())
myService.setSong_Path(songBeanList.get(currentindex).getPath());
else
myService.setSong_Path(songBeanList.get(songBeanList.size()-1).getPath());
}
else{//随机播放
currentindex=new Random().nextInt(songBeanList.size());
myService.setSong_Path(songBeanList.get(currentindex).getPath());
}
myService.init();
myService.start();
tv_currentname.setText(songBeanList.get(currentindex).getTitle());
songlist.smoothScrollToPosition(currentindex);
songlist.setSelection(currentindex);
playstatus=true;
mthread.start();
本文地址:https://blog.csdn.net/m0_47761892/article/details/107474001