zoukankan      html  css  js  c++  java
  • Android开发实战之简单音乐播放器

     最近开始学习音频相关。所以,很想自己做一个音乐播放器,于是,花了一天学习,将播放器的基本功能实现了出来。我觉得学习知识点还是蛮多的,所以写篇博客总结一下关于一个音乐播放器实现的逻辑。希望这篇博文对你的学习和生活有所帮助。效果图:

    **实现逻辑**

      在市面上的音乐播放app,即时你关了。那么一样会在后台播放,所以播放的逻辑应该写在Service中。并且能够实现Service和Activity之间进行通信。那么Service是四大组件之一,所以在使用的时候一定不要忘了在配置文件中声明一下。

         <service android:name="com.yakir.services.MusicService">
    
            </service>

    我们需要重写Service中的三个方法,onCreate(),onStartCommand(),onDestroy()

    onCreate():Service第一次启动的时候调用这个方法,可以做一些变量的初始化。

    onStartCommand():Service每一次启动的时候调用这个方法,可以在此方法写一些业务逻辑。

    onDestroy():Service销毁的时候调用,用于释放资源。

      接下来,如果需要播放一个音乐文件,可以使用安卓自带的播放器MediaPlayer,将播放逻辑封装起来:

        //开始
        public void start(String path) {
            try {
                mediaPlayer.reset();
                mediaPlayer.setDataSource(path);
                mediaPlayer.prepare();
                mediaPlayer.start();
                MediaUtils.currentState= Constants.PLAY_START;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //暂停
        public void pause (){
            if (mediaPlayer!=null&&mediaPlayer.isPlaying()) {
                mediaPlayer.pause();
                MediaUtils.currentState=Constants.PLAY_PAUSE;
            }
        }
        //继续播放
        public void continuePlay() {
            if (mediaPlayer!=null&&!mediaPlayer.isPlaying()) {
                mediaPlayer.start();
                MediaUtils.currentState= Constants.PLAY_START;
            }
        }
        //停止播放
        public void stop() {
            if (mediaPlayer!=null) {
                mediaPlayer.stop();
                MediaUtils.currentState=Constants.PLAY_STOP;
            }
        }

    我们知道,UI是写在Activity中的,那么就涉及到Activity与Service之间进行通信,他们之间通信的方式有5种,这里我是用了Intent,调用startService()进行通信,

    同时让Intent携带一组键值对数据,与Service端进行匹配。

    Activity:

       private void startMusicService(String option,String path) {
            Intent intentService = new Intent(MainActivity.this, MusicService.class);
            intentService.putExtra("option", option);
            intentService.putExtra("messenger",new Messenger(handler));
            intentService.putExtra("path", path);
            startService(intentService);
        }
        private void startMusicService(String option) {
            Intent intentService = new Intent(MainActivity.this, MusicService.class);
            intentService.putExtra("option", option);
            intentService.putExtra("messenger",new Messenger(handler));
            startService(intentService);
        }
        private void startMusicService(String option,int progress) {
            Intent intentService = new Intent(MainActivity.this, MusicService.class);
            intentService.putExtra("option", option);
            intentService.putExtra("progress",progress);
            intentService.putExtra("messenger",new Messenger(handler));
            startService(intentService);
        }
    

     Service:

        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            Log.e("thread",Thread.currentThread().getName() );
            String option=intent.getStringExtra("option");
            if (messenger==null) {
                messenger = (Messenger) intent.getExtras().get("messenger");
            }
            if ("开始".equals(option)) {
                start(intent.getStringExtra("path"));
            } else if ("暂停".equals(option)) {
                pause();
            } else if ("继续".equals(option)) {
                continuePlay();
            } else if ("停止".equals(option)) {
                stop();
            } else if ("跳转".equals(option)) {
                seekPlay(intent.getIntExtra("progress",-1));
            }
            return super.onStartCommand(intent, flags, startId);
        }

    这样,就实现了两者之间的通信,接下来,当我点击下一首的时候,那么下一个item的文字高亮,并且播放下一首歌。

    先从系统中拿到所有的音频数据:

       public static void getSongList (Context context) {
            musicBeanList.clear();
            Uri uri= MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
            Cursor cursor=context.getContentResolver().query(uri,
                    new String[]{
                            MediaStore.Audio.Media.TITLE,
                            MediaStore.Audio.Media.ARTIST,
                            MediaStore.Audio.Media.DATA},null,null,null);
            while (cursor.moveToNext()) {
                musicBeanList.add(new MusicBean(
                        cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.TITLE)),
                        cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST)),
                        cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA))));
            }
        }

    通过内容提供者,拿到系统的所有音频数据,以及音频的相关信息。DATA就是音频路径,拿到音频路径后就可以根据现实位置进行播放切换了。(这里很简单,不细说)

    处理文字高亮:

    我们需要知道当前的item位置和下一个item位置,当点击下一首歌曲,下个位置高亮,其他位置不亮。所以,需要我们定义一个常量记录当前位置,并且,当点击下一首,常量增加,上一首,常量减少。

       case R.id.ib_bottom_last:
                      setColor(Color.BLUE);
                      MediaUtils.currentPosition--;
                      setColor(Color.RED);
                      startMusicService("开始",MediaUtils.musicBeanList.get(MediaUtils.currentPosition).path);
                      imgBottomPlay.setImageResource(R.drawable.appwidget_pause);
                  break;
              case R.id.ib_bottom_next:
                      setColor(Color.BLUE);
                      MediaUtils.currentPosition++;
                      setColor(Color.RED);
                      startMusicService("开始",MediaUtils.musicBeanList.get(MediaUtils.currentPosition).path);
                      imgBottomPlay.setImageResource(R.drawable.appwidget_pause);
                  break;

    需要在改变颜色时做一下逻辑处理:

    当到最后一个item时点击下一个高亮变为第一个,当位于第一个时,点击上一首,高亮位于最后一个位置。

      private void setColor(int color) {
            if (MediaUtils.currentPosition==MediaUtils.musicBeanList.size()) {
                MediaUtils.currentPosition=0;
            }
            if (MediaUtils.currentPosition==-1) {
                MediaUtils.currentPosition=MediaUtils.musicBeanList.size()-1;
            }
            TextView textView= (TextView) songList.findViewWithTag(MediaUtils.currentPosition);
            if (textView!=null) {
                textView.setTextColor(color);
            }
    
        }

    接下来,需要实现一个更随音乐播放进度的进度条,这就需要实现Service向Activity的通信,可以通过消息机制,让Service发送消息给Activity,将播放信息传递给Activity.

    拿着这个Intent传一个信使(Messager).

    intentService.putExtra("messenger",new Messenger(handler));

    从而Service:

                                    Message message=Message.obtain();
                                    message.arg1=currentPostion;
                                    message.arg2=duration;
                                    message.what=Constants.MUSIC_PREPARE;
                                    messenger.send(message);

    Activity再处理:

        private Handler handler=new Handler(){
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case Constants.MUSIC_PREPARE:
                        int curduration=msg.arg1;
                        int totalduration=msg.arg2;
                        tv_curduration.setText(MediaUtils.duration2Str(curduration));
                        tv_totalduration.setText(MediaUtils.duration2Str(totalduration));
                        sk_duration.setMax(totalduration);
                        sk_duration.setProgress(curduration);
                        break;
                }
            }
        };

    在SeekBar中设置监听,当拖动停止时把当前进度传给Service,让音乐就当前位置播放:

       sk_duration.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
                @Override
                public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
    
                }
    
                @Override
                public void onStartTrackingTouch(SeekBar seekBar) {
    
                }
    
                @Override
                public void onStopTrackingTouch(SeekBar seekBar) {
                     sk_duration.setProgress(seekBar.getProgress());
                    startMusicService("跳转",seekBar.getProgress());
                }
            });

    同时,我们需要注意到一个情况,当启动电话时,音乐应该是停止状态,可以通过AudioManager获得音频焦点,当焦点失去时,音乐也应该停止:

         AudioManager audioManager= (AudioManager) getSystemService(Context.AUDIO_SERVICE);
            audioManager.requestAudioFocus(new AudioManager.OnAudioFocusChangeListener() {
                @Override
                public void onAudioFocusChange(int focusChange) {
                    switch (focusChange) {
                        case AudioManager.AUDIOFOCUS_GAIN:
                            mediaPlayer.start();
                            mediaPlayer.setVolume(1.f,2.0f);
                            break;
                        case AudioManager.AUDIOFOCUS_LOSS:
                            if (mediaPlayer.isPlaying())
                                mediaPlayer.stop();
                                mediaPlayer.release();
                                mediaPlayer=null;
                            break;
                        case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT:
                            if (mediaPlayer.isPlaying());
                            mediaPlayer.pause();
                            break;
                    }
    
                }
            },AudioManager.STREAM_MUSIC,AudioManager.AUDIOFOCUS_GAIN);

    好了,这样一个简单的音乐播放器就完成了,虽然说代码不是很困难,但是还是有很多知识点,比如Activity中Service中的通信,以及ListView相关,还有程序的逻辑性,所以我把几个重要的点总结了一下。希望这篇博文对你的生活和学习有所帮助,如果有什么疑问可以在下方留言,如果你想要源码,可以私聊我~

  • 相关阅读:
    scala
    数据结构(01)
    基本算法(07)
    基本算法(06)
    基本算法(05)
    git pull文件时和本地文件冲突的问题
    获取两个日期之间的日期形成一个集合
    lombok的简单介绍(2)
    springboot启动报错
    逆向工程的创建
  • 原文地址:https://www.cnblogs.com/lovelyYakir/p/5815866.html
Copyright © 2011-2022 走看看