sd卡本地音乐播放器

为了更好的对所学的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();}@Overridepublic void onCreate(SQLiteDatabase sqLiteDatabase) {String sql="create table song(id integer primary key autoincrement,title text,path text )";sqLiteDatabase.execSQL(sql);}@Overridepublic 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);}@Overridepublic int getCount() {return songList==null?0:songList.size();}@Overridepublic Object getItem(int i) {return songList.get(i);}@Overridepublic long getItemId(int i) {return i;}@Overridepublic 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);}elsemyViewHolder= (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();}elseinit();}//播放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() {@Overridepublic void onPrepared(MediaPlayer mediaPlayer) {mp.start();}});}elseinit();}//暂停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);}@Overridepublic void onCreate() {super.onCreate();init();初始化,准备播放}@Overridepublic void onDestroy() {if (mp!=null && mp.isPlaying()){mp.stop();mp.release();mp=null;}super.onDestroy();}@Overridepublic boolean onUnbind(Intent intent) {return super.onUnbind(intent);}@Overridepublic IBinder onBind(Intent intent) {return localBinder ;}
}

四、在主界面的各个控件的对播放进度信息的控制及显示

//声明创建Handler对象,处理线程发送的消息,更新进度条及当前时间和总时长

@SuppressLint("HandlerLeak")final  Handler mHandler=new Handler(){@Overridepublic 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;elsestrmin=minute+"";if (second<10)strsec="0"+second;elsestrsec=second+"";tv_totaltime.setText(strmin+":"+strsec);//歌曲当前播放时长minute=posi/1000/60;second=posi/1000%60;if (minute<10)strmin="0"+minute;elsestrmin=minute+"";if (second<10)strsec="0"+second;elsestrsec=second+"";tv_currenttime.setText(strmin+":"+strsec);break;default:break;}}};

//线程获取播放进度的百分比,并每隔10ms发送一次

Thread mthread=new Thread(new Runnable() {@Overridepublic 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() {@Overridepublic 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() {@Overridepublic void onProgressChanged(SeekBar seekBar, int i, boolean b) {}@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {}@Overridepublic void onStopTrackingTouch(SeekBar seekBar) {//手动调节进度int dest=seekBar.getProgress();int max=seekBar.getMax();myService.setProgress(max,dest);            }});

各个按钮的点击事件

@Overridepublic 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);//进度条归0tv_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());elsemyService.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();


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部