android音乐播放器开发

如何快速开发一款音乐播放器?

文末提供体验demo,实现了播放控制,进度更新,全网音乐免费下载,欢迎技术交流!

音乐播放器无非就是对mediaplayer对象的操作了,当然需要开启服务,而服务为了保活,只能使用前台服务。

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            startForegroundService(new Intent(mContext, MusicService.class));
   } else {	
            startService(new Intent(mContext, MusicService.class));
   }

启动前台服务后,你有5秒的时间发送服务通知,否则服务会被杀死并抛出异常

@Override
    public void onCreate() {
        super.onCreate();

        // 服务通知
        mNotification = createForegroundNotification();
        //将服务置于启动状态 ,NOTIFICATION_ID指的是创建的通知的ID
        startForeground(mNotificationId, mNotification);

创建服务通知

/**
     * 创建服务通知
     */
    private Notification createForegroundNotification() {

        mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        // 唯一的通知通道的id.
        String notificationChannelId = "notification_channel_music";

			//  Android8.0以上的系统,新建消息通道
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            //用户可见的通道名称
            String channelName = "音乐播放";
            //通道的重要程度
            int importance = NotificationManager.IMPORTANCE_NONE;
            NotificationChannel notificationChannel = new NotificationChannel(notificationChannelId, channelName, importance);
            notificationChannel.setDescription("音乐播放控制器");
            //LED灯
            notificationChannel.enableLights(false);
					// notificationChannel.setLightColor(Color.RED);
            //震动
            notificationChannel.setVibrationPattern(new long[]{0});
            notificationChannel.enableVibration(false);
            //声音
            notificationChannel.setSound(null,null);
            mNotificationManager.createNotificationChannel(notificationChannel);
        }

        mRemoteView = new RemoteViews(getPackageName(), R.layout.notification);

        initRemoteView(mRemoteView);


        NotificationCompat.Builder builder = new NotificationCompat.Builder(this, notificationChannelId)
                .setTicker("ticket")
                .setOngoing(true)//禁止侧滑删除
                //通知小图标
                .setSmallIcon(R.mipmap.logo)
                .setCustomContentView(mRemoteView)
                .setCustomBigContentView(mRemoteView)
                .setOnlyAlertOnce(true)//只响铃一次
                .setPriority(NotificationCompat.PRIORITY_LOW);//次要级通知,避免更新通知不断发出声音

//        创建通知并返回
        return builder.build();

    }

在这里插入图片描述

如何实现音乐的控制,通知栏控制器和app页面的控制器如何同步?

那么就要使用广播机制了,这里我定义了一些抽象方法,然后在BroadcastReceiver中处理这些事件

public abstract class MusicCallback{

    public void init(Context context, Intent intent) {}

    public void inited(Context context, Intent intent){}

    public void onMusicStart(Context context, Intent intent){}

    public void onMusicError(Context context, Intent intent){}

    public void onMusicRemove(Context context, Intent intent){}

    public void onMusicRemoveAll(Context context, Intent intent){}

    public void onMusicProgressUpdate(Context context, Intent intent){}

    public void clickPlayThisObj(Context context, Intent intent){}

    public void clickPlayListAddButton(Context context, Intent intent){}

    public void clickPlayButton(Context context, Intent intent){}

    public void clickPlayBeforeButton(Context context, Intent intent){}

    public void clickPlayAfterButton(Context context, Intent intent){}

    public void clickPlayModeButton(Context context, Intent intent){}


}

其实就是一些交互事件的方法,主要有,播放,上一曲,下一曲,模式切换(单曲/多曲循环)等等。这些基本满足了一个音乐控制器所有的交互事件!
在这里插入图片描述

然后在需要音乐控制器的地方实现以下代码可以实现交互了:

mReceiver = new MusicBroadcastReceiver(mContext, mMusicDialogCallback)
                .addFilter(MusicOpra.MUSIC_START)
                .addFilter(MusicOpra.MUSIC_ERROR)
                .addFilter(MusicOpra.MUSIC_LIST_ADD)
                .addFilter(MusicOpra.MUSIC_PROGRESS_UPDATE)
                .addFilter(MusicOpra.MUSIC_INITED)
                .register();


 @Override
    protected void onClickEvent(View view) {
        switch (view.getId()){
            case R.id.playIv:
                mContext.sendBroadcast(new Intent(MusicOpra.MUSIC_PLAY_PAUSE));
                break;
            case R.id.playBeforeIv:
                mContext.sendBroadcast(new Intent(MusicOpra.MUSIC_PLAY_BEFORE));
                break;
            case R.id.playAfterIv:
                mContext.sendBroadcast(new Intent(MusicOpra.MUSIC_PLAY_AFTER));
                break;
            case R.id.playModeIv:
                mContext.sendBroadcast(new Intent(MusicOpra.MUSIC_PLAY_MODE));
                break;
        }
    }


private MusicCallback mMusicDialogCallback = new MusicCallback() {

        private SingBean mSingBean;
        private boolean isPrepared;
        private boolean isPlaying;
        private int playMode;


        @Override
        public void inited(Context context, Intent intent) {
            mSingBean = (SingBean) intent.getSerializableExtra(MusicOpra.KEY_MUSIC_BEAN);
            isPrepared = intent.getBooleanExtra(MusicOpra.KEY_MUSIC_PREPARED, false);
            isPlaying = intent.getBooleanExtra(MusicOpra.KEY_MUSIC_ISPLAYING, false);
            playMode = intent.getIntExtra(MusicOpra.KEY_MUSIC_PLAY_MODE, 0);

            if (playMode == 0) {
                playModeIv.setImageResource(R.drawable.icon_turn_all);
            } else {
                playModeIv.setImageResource(R.drawable.icon_turn_single);
            }

            if (isPlaying) {
                playIv.setImageResource(R.drawable.pause);
            } else {
                playIv.setImageResource(R.drawable.play);
            }

            if (mSingBean!=null){
                singNameTv.setText(mSingBean.getSingName());
            }
            progressBar.setProgress(intent.getIntExtra(MusicOpra.KEY_MUSIC_PROGRESS, 0));
        }

        @Override
        public void clickPlayButton(Context context, Intent intent) {
            if (mSingBean != null) {
                if (isPrepared) {
                    if (!isPlaying) {
                        playIv.setImageResource(R.drawable.pause);
                        isPlaying = true;
                    } else {
                        playIv.setImageResource(R.drawable.play);
                        isPlaying = false;
                    }
                } else {
                    mContext.sendBroadcast(new Intent(MusicOpra.MUSIC_PLAY_THIS).putExtra(MusicOpra.KEY_MUSIC_BEAN, mSingBean));
                }
            } else {
                mContext.sendBroadcast(new Intent(MusicOpra.MUSIC_ERROR).putExtra(MusicOpra.KEY_MUSIC_ERROR, MusicService.MUSIC_ERROR_NODATA));
            }
        }

        @Override
        public void clickPlayModeButton(Context context, Intent intent) {
            if (playMode == 0) {//当前是多曲循环
                playModeIv.setImageResource(R.drawable.icon_turn_single);
                playMode = 1;
            } else {
                playModeIv.setImageResource(R.drawable.icon_turn_all);
                playMode = 0;
            }
        }

        @Override
        public void clickPlayListAddButton(Context context, Intent intent) {
            if (getActivity() instanceof MainActivity){
                ToastUtil.showShort(mContext, "已添加到播放列表");
            }
        }

        @Override
        public void onMusicStart(Context context, Intent intent) {
            isPrepared = true;
            isPlaying=true;
            mSingBean = (SingBean) intent.getSerializableExtra(MusicOpra.KEY_MUSIC_BEAN);

            singNameTv.setText(mSingBean.getSingName());
            playIv.setImageResource(R.drawable.pause);
            progressBar.setProgress(0);

        }

        @Override
        public void onMusicError(Context context, Intent intent) {
            //播放错误
            switch (intent.getIntExtra(MusicOpra.KEY_MUSIC_ERROR, 1)) {
                case MediaPlayer.MEDIA_ERROR_IO:
                    singNameTv.setText("无法播放:MEDIA_ERROR_IO");
                case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
                    singNameTv.setText("无法播放:MEDIA_ERROR_SERVER_DIED");
                    break;
                case MediaPlayer.MEDIA_ERROR_TIMED_OUT:
                    singNameTv.setText("无法播放:MEDIA_ERROR_TIMED_OUT");
                    break;
                case MediaPlayer.MEDIA_ERROR_UNKNOWN:
                case MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK://无效的进度操作
                    singNameTv.setText("无法播放:MEDIA_ERROR_UNKNOWN");
                    break;
                case MediaPlayer.MEDIA_ERROR_UNSUPPORTED://不支持的格式
                case MediaPlayer.MEDIA_ERROR_MALFORMED://码流有问题,不支持
                    singNameTv.setText("无法播放:MEDIA_ERROR_UNSUPPORTED");
                    break;
                case MusicService.MUSIC_ERROR_NODATA:
                    singNameTv.setText("播放列表无可播放歌曲!");
                    break;
            }
            playIv.setImageResource(R.drawable.play);
        }

        @Override
        public void onMusicProgressUpdate(Context context, Intent intent) {
            int progress = intent.getIntExtra(MusicOpra.KEY_MUSIC_PROGRESS, 0);
            progressBar.setProgress(progress);
        }

比如你还需要在播放列表展示控制器
在这里插入图片描述

附上体验demo:
在这里插入图片描述

以上是音乐播放器的实现思路。

源码已在gitee上开源,欢迎一起技术交流学习!

https://gitee.com/jhone/music

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一鱼浅游

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值