欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

sd卡本地音乐播放器

程序员文章站 2022-07-10 18:55:20
为了更好的android的内容进行综合使用作,以及提供给更入门Android做为一个领路的文章,简单的制作了一个音乐播放器,实现简单的拖动进度条实现快进退功能以及其他的上一曲、下一曲、开始/暂停、 停止简单、播放模式等功能,用到了listview、SQLite、seekbar,button等常见组件。实现的结果如图所示:显示并播放music文件夹内的600多首mp3音乐。......

为了更好的对所学的android的内容进行综合使用,简单的制作了一个音乐播放器,实现简单的拖动进度条实现快进退功能以及其他的上一曲、下一曲、开始/暂停、 停止简单、播放模式等功能,用到了listview、SQLite、seekbar,button等常见组件。实现的结果如图所示:显示并播放music文件夹内的600多首mp3音乐。
sd卡本地音乐播放器
一、歌曲信息的存储----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