android 应用内音乐播放器

介绍一种实现应用内音乐播放器方法:支持通用播控、后台播放、通知栏显示控制播放、退出播放界面时创建全局可拖动的悬浮窗控制播放。

效果图如下:

实现思路:

1.后台播放首先想到使用Service,同时要与activity通讯进行播控,此时一般通过bindService实现

2.通知栏显示并要能进行播控。使用Notification+RemoteViews实现通知栏显示UI并通过RemoteView可以发送广播特性来实现跟Service播放通讯。

3.全局悬浮窗播控,使用WindownManager.addView()显示,由于上一步通知栏是通过广播与播放器进行通讯,这里也统一使用相同的广播进行通讯即可。

小结:Service中实现播放逻辑,并接收各方广播进行控制播放,在开始播放时创建Notification通知栏。Activity绑定Service,直接通过Binder与Service通讯进行控制,当然也可以通过广播控制。退出activity时通过WindownManager创建全局悬浮窗.

主要代码如下:

MusicPlayerService.java  实现播放

import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.BitmapFactory;
import android.media.MediaPlayer;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.text.TextUtils;
import android.util.Log;
import android.widget.RemoteViews;

import androidx.core.app.NotificationCompat;

import com.justlink.nas.R;
import com.justlink.nas.application.MyApplication;
import com.justlink.nas.bean.FileBean;
import com.justlink.nas.constans.MyConstants;
import com.justlink.nas.utils.LogUtil;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

public class MusicPlayerService extends Service {
    public static final String TAG = "MusicService";
    /**
     * 发送音乐播放控制的广播给MianActivity,音乐的控制统一交给MainActivity管理
     * 下一首,暂停,上一首,播放,继续播放
     */
    private static final String ACTION_NEXT_SONG = "com.justlink.action.nextsong";
    private static final String ACTION_PAUSE = "com.justlink.action.pause";
    private static final String ACTION_PRE_SONG = "com.justlink.action.presong";
    private static final String ACTION_PLAY_SONG = "com.justlink.action.playsong";
    private static final String ACTION_PLAY_CLOSE = "com.justlink.action.close";
    private static final String ACTION_CONTINUE_PLAYING_SONG = "com.justlink.action.continueplaying";
    public MusicBinder mBinder;
    private MediaPlayer mPlayer;
    private Handler handler;
    private Timer timer;
    private int duration,currentPlayIndex;
    private String defaultSongName;
    //观察者们,播放进度更新时通知他们
    private List<Watcher> watcherList = new ArrayList<Watcher>();
    private MyBroadCastReceiver myBroadCastReceiver;
    /**
     * 通知
     */
    private static Notification notification;
    /**
     * 通知栏视图
     */
    private static RemoteViews remoteViews;
    /**
     * 通知ID
     */
    private int NOTIFICATION_ID = 1;
    /**
     * 通知管理器
     */
    private static NotificationManager manager;

    private FileBean currentPlayFile;

    public MusicPlayerService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        return mBinder;
      //  throw new UnsupportedOperationException("Not yet implemented");
    }

    public class MusicBinder extends Binder {

        public MusicPlayerService getService() {
            return MusicPlayerService.this;
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();
        mBinder = new MusicBinder();
        mPlayer = new MediaPlayer();

        timer = new Timer();
        timer.scheduleAtFixedRate(new TimerTask() {
            public void run() {
                if (mPlayer.isPlaying()) {
                    Log.d(TAG, "start update proress...");
                    //播放进度更新通知观察者
                    for (Watcher watcher : watcherList) {
                        watcher.update(mPlayer.getCurrentPosition(),duration);
                        handler.sendEmptyMessage(5562);
                    }
                }
            }

        }, 1000, 1000);

        //初始化RemoteViews配置
        initRemoteViews();
        //初始化通知
        initNotification();

        Log.d(TAG, "onCreate");
        myBroadCastReceiver = new MyBroadCastReceiver();
        IntentFilter filter = new IntentFilter();
        filter.addAction(ACTION_NEXT_SONG);
        filter.addAction(ACTION_PAUSE);
        filter.addAction(ACTION_PRE_SONG);
        filter.addAction(ACTION_PLAY_SONG);
        filter.addAction(ACTION_PLAY_CLOSE);
        filter.addAction(ACTION_CONTINUE_PLAYING_SONG);
        registerReceiver(myBroadCastReceiver,filter);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, "onStartCommnad");
        if(intent!=null && intent.getStringExtra("url")!=null){
            String path = intent.getStringExtra("url");
            int position = intent.getIntExtra("currentPosition",0);
            defaultSongName = intent.getStringExtra("name");
            play(path);
            changePlayProgress(position);
        }
       // showButtonNotify();
        return START_STICKY;
    }

    public void addWatcher(Watcher watcher) {
        watcherList.add(watcher);
    }

    public void removeWatcher(Watcher watcher) {
        watcherList.remove(watcher);
    }

    public interface Watcher {
        public void update(int currentProgress,int duration);
    }

    public void play(String url) {
        try {
            mPlayer.reset();
            Log.d(TAG, "play reset ");
            mPlayer.setDataSource(url);
            Log.d(TAG, "play setDataSource ");
            mPlayer.prepare();
            Log.d(TAG, "play prepare ");
            mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {

                @Override
                public void onCompletion(MediaPlayer player) {
                    if(handler != null)
                        handler.sendMessage(handler.obtainMessage(5563));
                    Log.d(TAG, "sendBroadcast->nextsong");
                }
            });
            mPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                @Override
                public void onPrepared(MediaPlayer mediaPlayer) {
                    duration = mPlayer.getDuration();
                    LogUtil.showLog(TAG,"==duration=="+duration);
                    mPlayer.start();
                    Log.d(TAG, "play start ");
                    updateNotificationShow();
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void pauseMusic() {
        mPlayer.pause();
    }

    public void continuePlaying() {
        mPlayer.start();
    }

    public void stopMusic(){
        mPlayer.stop();
    };

    public void changePlayProgress(int pos) {
        mPlayer.seekTo(pos);
    }

    public void setHandler(Handler handler) {
        this.handler = handler;
    }

    public void setCurrentPlayIndex(int index){
        currentPlayIndex = index;
    }

    public void setDefaultSongName(String defaultSongName) {
        this.defaultSongName = defaultSongName;
    }

    private class MyBroadCastReceiver extends BroadcastReceiver{

        @Override
        public void onReceive(Context context, Intent intent) {
            LogUtil.showLog(TAG,"==action=="+intent.getAction());
            switch (intent.getAction()){
                case ACTION_PLAY_SONG:
                    if(!mPlayer.isPlaying())
                        mPlayer.start();
                    updateNotificationShow();
                    break;
                case ACTION_PAUSE:
                    if(mPlayer.isPlaying())
                        mPlayer.pause();
                    updateNotificationShow();
                    break;
                case ACTION_NEXT_SONG:
                    currentPlayIndex++;
                    playNextOrLast();
                    break;
                case ACTION_PRE_SONG:
                    if(currentPlayIndex==0)
                        currentPlayIndex = MyApplication.audioList.size()-1;
                    currentPlayIndex--;
                    playNextOrLast();
                     break;
                case ACTION_PLAY_CLOSE:
                    manager.cancel(NOTIFICATION_ID);
                    break;

                case ACTION_CONTINUE_PLAYING_SONG:
                    break;
            }
        }
    }

    public void playNextOrLast(){
        if(!mPlayer.isPlaying())
            mPlayer.pause();
        mPlayer.stop();
        String path = "";
        FileBean fileBean = MyApplication.audioList.get(currentPlayIndex);
        if(TextUtils.isEmpty(fileBean.getDir()))
            path = fileBean.getName();
        else
            path = fileBean.getDir()+"/"+fileBean.getName();
        String currentUrl = MyConstants.file_http_base_url+path+"?disk="+ MyApplication.storeList.get(MyApplication.currentStoreId).getPosition()+"&user="+MyApplication.userLoginID+"&device_id="+MyApplication.currentDevID+"&filetype=data";
        play(currentUrl);
        //歌曲名
        remoteViews.setTextViewText(R.id.tv_notification_song_name,fileBean.getName().substring(0,fileBean.getName().lastIndexOf(".")));
        //发送通知
        manager.notify(NOTIFICATION_ID, notification);
    }

    /**
     * 初始化自定义通知栏 的按钮点击事件
     */
    private void initRemoteViews() {
        remoteViews = new RemoteViews(this.getPackageName(), R.layout.notification);

        //通知栏控制器上一首按钮广播操作
        Intent intentPrev = new Intent(ACTION_PRE_SONG);
        PendingIntent prevPendingIntent = PendingIntent.getBroadcast(this, 5100, intentPrev, PendingIntent.FLAG_CANCEL_CURRENT);
        //为prev控件注册事件
        remoteViews.setOnClickPendingIntent(R.id.btn_notification_previous, prevPendingIntent);


        //通知栏控制器播放暂停按钮广播操作  //用于接收广播时过滤意图信息
        Intent intentPlay = new Intent(ACTION_PAUSE);
        PendingIntent playPendingIntent = PendingIntent.getBroadcast(this, 5101, intentPlay, PendingIntent.FLAG_CANCEL_CURRENT);
        //为play控件注册事件
        remoteViews.setOnClickPendingIntent(R.id.btn_notification_play, playPendingIntent);

        //通知栏控制器下一首按钮广播操作
        Intent intentNext = new Intent(ACTION_NEXT_SONG);
        PendingIntent nextPendingIntent = PendingIntent.getBroadcast(this, 5102, intentNext, PendingIntent.FLAG_CANCEL_CURRENT);
        //为next控件注册事件
        remoteViews.setOnClickPendingIntent(R.id.btn_notification_next, nextPendingIntent);

        //通知栏控制器关闭按钮广播操作
        Intent intentClose = new Intent(ACTION_PLAY_CLOSE);
        PendingIntent closePendingIntent = PendingIntent.getBroadcast(this, 5103, intentClose, 0);
        //为close控件注册事件
        remoteViews.setOnClickPendingIntent(R.id.btn_notification_close, closePendingIntent);

    }

    /**
     * 初始化通知
     */
    @SuppressLint("NotificationTrampoline")
    private void initNotification() {
        String channelId = "play_control";
        String channelName = "播放控制";
        int importance = NotificationManager.IMPORTANCE_HIGH;
        createNotificationChannel(channelId, channelName, importance);

        //点击整个通知时发送广播
        Intent intent = new Intent(getApplicationContext(), NotificationClickReceiver.class);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0,
                intent, FLAG_UPDATE_CURRENT);

        //初始化通知
        notification = new NotificationCompat.Builder(this, "play_control")
                .setContentIntent(pendingIntent)
                .setWhen(System.currentTimeMillis())
                .setSmallIcon(R.mipmap.ic_launcher)
                .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
                .setCustomContentView(remoteViews)
                .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
                .setAutoCancel(false)
                .setOnlyAlertOnce(true)
                .setOngoing(true)
                .build();
    }


    /**
     * 创建通知渠道
     *
     * @param channelId   渠道id
     * @param channelName 渠道名称
     * @param importance  渠道重要性
     */
    @TargetApi(Build.VERSION_CODES.O)
    private void createNotificationChannel(String channelId, String channelName, int importance) {
        NotificationChannel channel = new NotificationChannel(channelId, channelName, importance);
        channel.enableLights(false);
        channel.enableVibration(false);
        channel.setVibrationPattern(new long[]{0});
        channel.setSound(null, null);
        manager = (NotificationManager) getSystemService(
                NOTIFICATION_SERVICE);
        manager.createNotificationChannel(channel);
    }

    /**
     * 更改通知的信息和UI
     */
    public void updateNotificationShow() {
        //通知栏控制器播放暂停按钮广播操作  //用于接收广播时过滤意图信息
        Intent intentPlay = new Intent(mPlayer.isPlaying()?ACTION_PAUSE:ACTION_PLAY_SONG);
        PendingIntent playPendingIntent = PendingIntent.getBroadcast(this, 5101, intentPlay, PendingIntent.FLAG_CANCEL_CURRENT);
        //为play控件注册事件
        remoteViews.setOnClickPendingIntent(R.id.btn_notification_play, playPendingIntent);
        //播放状态判断
        if (mPlayer.isPlaying()) {
            remoteViews.setImageViewResource(R.id.btn_notification_play, R.mipmap.notify_pause);
        } else {
            remoteViews.setImageViewResource(R.id.btn_notification_play, R.mipmap.notify_play);
        }
        //封面专辑
        remoteViews.setImageViewResource(R.id.iv_album_cover,R.mipmap.ic_launcher);
        //歌曲名
        remoteViews.setTextViewText(R.id.tv_notification_song_name,defaultSongName.substring(0,defaultSongName.lastIndexOf(".")));
        //歌手名
        remoteViews.setTextViewText(R.id.tv_notification_singer,"歌星");
        //发送通知
        manager.notify(NOTIFICATION_ID, notification);
    }


    @Override
    public void onDestroy() {
        Log.d(TAG, "musicService:onDestroy");
        timer.cancel();
        if (mBinder != null) mBinder = null;
        handler = null;
        if (mPlayer != null) {
            mPlayer.release();
            mPlayer = null;
        }
        manager.cancel(NOTIFICATION_ID);
        unregisterReceiver(myBroadCastReceiver);
        super.onDestroy();
    }

    public FileBean getCurrentPlayFile() {
        return currentPlayFile;
    }

    public void setCurrentPlayFile(FileBean currentPlayFile) {
        this.currentPlayFile = currentPlayFile;
    }
}

 WindowUtils.java 实现全局悬浮窗

package com.justlink.nas.ui.musicplayer;

import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.TextView;

import com.justlink.nas.R;
import com.justlink.nas.utils.LogUtil;
import com.justlink.nas.utils.ScreenUtils;

public class WindowUtils {

    private static final String LOG_TAG = "WindowUtils";
    private static View mView = null;
    private static WindowManager mWindowManager = null;
    private static Context mContext = null;
    public static Boolean isShown = false;
    public static boolean isPlaying = true;
    private static final String ACTION_PAUSE = "com.justlink.action.pause";
    private static final String ACTION_PLAY_SONG = "com.justlink.action.playsong";
    private static final String ACTION_PLAY_CLOSE = "com.justlink.action.close";
    /**
     * 显示弹出框
     * @param context
     */

    public static void showPopupWindow(final Context context,String title) {

        if (isShown) {
            LogUtil.showLog(LOG_TAG, "return cause already shown");
            return;
        }
        isShown = true;
        LogUtil.showLog(LOG_TAG, "showPopupWindow");
        // 获取应用的Context
        mContext = context.getApplicationContext();
        // 获取WindowManager
        mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
        mView = setUpView(context,title);
        final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
        // 类型
        params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        // WindowManager.LayoutParams.TYPE_SYSTEM_ALERT
        // 设置flag
        int flags = /*WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM | */WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
        // 如果设置了WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,弹出的View收不到Back键的事件
        params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
        // 不设置这个弹出框的透明遮罩显示为黑色
        params.format = PixelFormat.TRANSLUCENT;
        // FLAG_NOT_TOUCH_MODAL不阻塞事件传递到后面的窗口
        // 设置 FLAG_NOT_FOCUSABLE 悬浮窗口较小时,后面的应用图标由不可长按变为可长按
        // 不设置这个flag的话,home页的划屏会有问题
        params.width = WindowManager.LayoutParams.WRAP_CONTENT;
        params.height = WindowManager.LayoutParams.WRAP_CONTENT;
        params.x = ScreenUtils.getScreenWidth(mContext);
        params.y = ScreenUtils.getScreenHeight(mContext) - ScreenUtils.dip2px(mContext,100);
      //  params.gravity = Gravity.RIGHT;
        mWindowManager.addView(mView, params);
        mView.setOnTouchListener(new View.OnTouchListener() {
            private int initialX;
            private int initialY;
            private float initialTouchX;
            private float initialTouchY;

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        initialX = params.x;
                        initialY = params.y;
                        initialTouchX = event.getRawX();
                        initialTouchY = event.getRawY();
                        return true;
                    case MotionEvent.ACTION_UP:
                        return true;
                    case MotionEvent.ACTION_MOVE:
                        params.x = initialX + (int) (event.getRawX() - initialTouchX);
                        params.y = initialY + (int) (event.getRawY() - initialTouchY);
                        mWindowManager.updateViewLayout(mView, params);
                        return true;
                }
                return false;
            }
        });
        LogUtil.showLog(LOG_TAG, "add view");
    }

    /**
     * 隐藏弹出框
     */

    public static void hidePopupWindow() {
        LogUtil.showLog(LOG_TAG, "hide " + isShown + ", " + mView);
        if (isShown && null != mView) {
            LogUtil.showLog(LOG_TAG, "hidePopupWindow");
            mWindowManager.removeView(mView);
            isShown = false;
        }

    }

    private static View setUpView(final Context context,String title) {
        LogUtil.showLog(LOG_TAG, "setUp view");
        View view = LayoutInflater.from(context).inflate(R.layout.popupwindow_music_player, null);
        ImageView positiveBtn = (ImageView) view.findViewById(R.id.iv_play_pause);
        positiveBtn.setImageResource(isPlaying?R.mipmap.small_pause:R.mipmap.small_play);
        TextView tvTitle = view.findViewById(R.id.tv_song_name);
        tvTitle.setText(title);
       // tvTitle.setHorizontallyScrolling(true);
       // tvTitle.setMarqueeRepeatLimit(-1);
        positiveBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                LogUtil.showLog(LOG_TAG, "ok on click");
                isPlaying = !isPlaying;
                context.sendBroadcast(new Intent(isPlaying?ACTION_PLAY_SONG:ACTION_PAUSE));
                positiveBtn.setImageResource(isPlaying?R.mipmap.small_pause:R.mipmap.small_play);
            }
        });

        ImageView negativeBtn = (ImageView)view.findViewById(R.id.iv_close);
        negativeBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                LogUtil.showLog(LOG_TAG, "cancel on click");
                context.sendBroadcast(new Intent(ACTION_PAUSE));
                context.sendBroadcast(new Intent(ACTION_PLAY_CLOSE));
                WindowUtils.hidePopupWindow();
                Intent intent = new Intent(context, MusicPlayerService.class);
                context.stopService(intent);
            }
        });

        // 点击窗口外部区域可消除
        // 这点的实现主要将悬浮窗设置为全屏大小,外层有个透明背景,中间一部分视为内容区域
        // 所以点击内容区域外部视为点击悬浮窗外部
/*        final View popupWindowView = view.findViewById(R.id.popup_window);// 非透明的内容区域

        view.setOnTouchListener(new View.OnTouchListener() {

            @Override

            public boolean onTouch(View v, MotionEvent event) {

                LogUtil.i(LOG_TAG, "onTouch");

                int x = (int) event.getX();

                int y = (int) event.getY();

                Rect rect = new Rect();

                popupWindowView.getGlobalVisibleRect(rect);

                if (!rect.contains(x, y)) {

                    WindowUtils.hidePopupWindow();

                }

                LogUtil.showLog(LOG_TAG, "onTouch : " + x + ", " + y + ", rect: " + rect);

                return false;

            }

        });*/

        // 点击back键可消除

        view.setOnKeyListener(new View.OnKeyListener() {
            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                switch (keyCode) {
                    case KeyEvent.KEYCODE_BACK:
                        WindowUtils.hidePopupWindow();
                        return true;
                    default:
                        return false;

                }
            }
        });

        return view;

    }

    public static void setIsPlaying(boolean isPlaying) {
        WindowUtils.isPlaying = isPlaying;
    }
}
MusicPlayerActivity.java 实现主播放界面
 // 绑定服务时的ServiceConnection参数
    private ServiceConnection conn = new ServiceConnection() {

        // 绑定成功后该方法回调,并获得服务端IBinder的引用
        public void onServiceConnected(ComponentName name, IBinder service) {
            // 通过获得的IBinder获取PlayMusicService的引用
            musicService = ((MusicPlayerService.MusicBinder) service).getService();
            musicService.addWatcher(MusicPlayerActivity.this);
            musicService.setHandler(myHandler);
            if("notify".equals(from)){
                fileBean = musicService.getCurrentPlayFile();
                currentSongName = fileBean.getName();
                String path = getFilePath(fileBean);
                currentUrl = MyConstants.file_http_base_url + path + "?disk=" + fileBean.getRootPath() + "&user=" + getOwner(fileBean) + "&device_id=" + MyApplication.currentDevID + "&filetype=data";
                myViewBinding.tvSongName.setText(currentSongName);
                LogUtil.showLog("music","==name=="+currentSongName+"==path=="+path+"==url=="+currentUrl);
            }else {
               
                    String path = getFilePath(fileBean);
                    currentUrl = MyConstants.file_http_base_url + path + "?disk=" + fileBean.getRootPath() + "&user=" + getOwner(fileBean) + "&device_id=" + MyApplication.currentDevID + "&filetype=data";
                
                musicService.setCurrentPlayFile(fileBean);
                musicService.play(currentUrl);
            }

            musicService.setDefaultSongName(currentSongName);
            goPlaylist();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.d(TAG, "onServiceDisconnected:musicService");
        }

    };

    // 绑定服务MusicService
    private void bindToService() {
        bindService(new Intent(this, MusicPlayerService.class), conn, Service.BIND_AUTO_CREATE);
    }

.....

    @Override
    protected void onResume() {
        super.onResume();
        if(!"notify".equals(from))
            showLoadingDialog(true, getString(R.string.image_loading));
        WindowUtils.hidePopupWindow();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { // 如果API级别大于等于23(Android 6.0)
            if (!Settings.canDrawOverlays(MusicPlayerActivity.this)) {
                Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                        Uri.parse("package:" + getPackageName()));
                startActivityForResult(intent, 13001);
            }
        }

        Intent intent = new Intent(this, MusicPlayerService.class);
        startService(intent);
    }

    @Override
    protected void onStart() {
        super.onStart();
    }

    @Override
    protected void onClickTitleBack() {
        goBackByQuick();
    }

    @Override
    public void onClick(View v) {
        super.onClick(v);
        switch (v.getId()) {
            case R.id.iv_play_mode: //播放模式
                currentPlayMode++;
                if (currentPlayMode == 3)
                    currentPlayMode = 0;
                myViewBinding.ivPlayMode.setImageResource(cycleViewResource[currentPlayMode]);
                break;
            case R.id.iv_play_last: //上一曲
                isPlaying = true;
                myViewBinding.ivPlayPause.setImageResource(R.mipmap.icon_pause);
                switch (currentPlayMode) {
                    case 0: //单曲循环
                        if (isPlaying) {
                            musicService.pauseMusic();
                            musicService.stopMusic();
                        }
                        musicService.play(currentUrl);
                        break;
                    case 1: //列表循环
                    case 2: //顺序播放
                        if ("last_record".equals(from)) { //最近上传记录
                            musicService.play(currentUrl);
                            break;
                        }
                        if (currentPlayIndex == 0)
                            currentPlayIndex = fileList.size() - 1;
                        else
                            currentPlayIndex -= 1;
                        musicService.setCurrentPlayIndex(currentPlayIndex);
                        String path = "";
                        FileBean fileBean = fileList.get(currentPlayIndex);
                       musicService.setCurrentPlayFile(fileBean);
                        hasFav = fileBean.getFavMode() == 1;
                        path = getFilePath(fileBean);
                        currentUrl = MyConstants.file_http_base_url + path + "?disk=" + fileBean.getRootPath() + "&user=" + getOwner(fileBean) + "&device_id=" + MyApplication.currentDevID + "&filetype=data";
                        musicService.play(currentUrl);
                        break;
                }
                currentSongName = fileList.get(currentPlayIndex).getName();
                myViewBinding.tvSongName.setText(currentSongName);
                break;
            case R.id.iv_play_pause: //播放暂停
                isPlaying = !isPlaying;
                if (isPlaying) {
                    myViewBinding.ivPlayPause.setImageResource(R.mipmap.icon_pause);
                    sendBroadcast(new Intent(ACTION_PLAY_SONG));
                    myViewBinding.ivAnim.startAnimation(playAnimation);
                } else {
                    myViewBinding.ivPlayPause.setImageResource(R.mipmap.icon_play);
                    sendBroadcast(new Intent(ACTION_PAUSE));
                    myViewBinding.ivAnim.clearAnimation();
                }
                break;
            case R.id.iv_play_next: //下一曲
                isPlaying = true;
                myViewBinding.ivPlayPause.setImageResource(R.mipmap.icon_pause);
                if ("last_record".equals(from)) { //最近上传记录
                    musicService.play(currentUrl);
                    break;
                }
                if (currentPlayIndex == fileList.size())
                    currentPlayIndex = 0;
                String path = "";
                FileBean fileBean = fileList.get(currentPlayIndex);
                musicService.setCurrentPlayFile(fileBean);
                hasFav = fileBean.getFavMode() == 1;
                path = getFilePath(fileBean);
                currentUrl = MyConstants.file_http_base_url + path + "?disk=" + fileBean.getRootPath() + "&user=" + getOwner(fileBean) + "&device_id=" + MyApplication.currentDevID + "&filetype=data";
                musicService.play(currentUrl);
                currentSongName = fileList.get(currentPlayIndex).getName();
                myViewBinding.tvSongName.setText(currentSongName);
                currentPlayIndex += 1;
                musicService.setCurrentPlayIndex(currentPlayIndex);
                break;
            case R.id.iv_play_list: //播放列表
                if ("last_record".equals(from)) { //最近上传记录
                    ToastUtil.showToastShort(getString(R.string.no_more_song));
                    break;
                }
                new PlayListDialog(currentPlayIndex, currentPlayMode, new PlayListDialog.DialogListen() {
                    @Override
                    public void onItemClick(int position) {
                        if (isPlaying) {
                            musicService.pauseMusic();
                            musicService.stopMusic();
                        }
                        String path = "";
                        FileBean fileBean = fileList.get(position);
                        musicService.setCurrentPlayFile(fileBean);
                        hasFav = fileBean.getFavMode() == 1;
                        path = getFilePath(fileBean);
                        currentUrl = MyConstants.file_http_base_url + path + "?disk=" + fileBean.getRootPath() + "&user=" + getOwner(fileBean) + "&device_id=" + MyApplication.currentDevID + "&filetype=data";
                        musicService.play(currentUrl);
                    }

                    @Override
                    public void onDelete(int position) {
                        fileList.remove(position);
                    }

                    @Override
                    public void onModeChange(int mode) {
                        currentPlayMode = mode;
                        if (currentPlayMode == 3)
                            currentPlayMode = 0;
                        myViewBinding.ivPlayMode.setImageResource(cycleViewResource[currentPlayMode]);
                    }

                    @Override
                    public void onClean() {
                        fileList.clear();
                    }
                }, fileList).showNow(getSupportFragmentManager(), "");
                break;
            case R.id.toolbar_right_tv: //收藏
                //  hasFav = !hasFav;
                showLoadingDialog(true);
                FileBean fileBean1 = fileList.get(currentPlayIndex);
                path = getFilePath(fileBean1);
                TcpClient.getInstance().sendMessage(JsonUtils.getInstance().formtFavFileOperationJson(hasFav ? "delete" : "add", fileBean1.getRootPath(), new String[]{path}));
                break;
        }
    }

    @Override
    public void update(int currentProgress, int duration) {
        //   LogUtil.showLog(TAG,"==current play position=="+currentProgress+"==duration=="+duration);
        currentPlayPosition = currentProgress;
        totalDuration = duration;
    }

    @Override
    protected void onPause() {
        super.onPause();
      /*  Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                Uri.parse("package:" + getPackageName()));
        startActivityForResult(intent,11002);*/
        WindowUtils.setIsPlaying(isPlaying);
        WindowUtils.showPopupWindow(getApplicationContext(), currentSongName);
    }

    protected void onDestroy() {
        //  musicService = null;
        this.unbindService(conn);
      /*   Intent intent = new Intent(this, MusicPlayerService.class);
        intent.putExtra("url",currentUrl);
        intent.putExtra("currentPosition",currentPlayPosition);
        intent.putExtra("name",currentSongName);
        startService(intent);*/
        super.onDestroy();
    }

通过广播监听点击通知栏跳转到主播放界面:

/**
 * 通知点击广播接收器  跳转到栈顶的Activity ,而不是new 一个新的Activity
 *
 * @author llw
 */
public class NotificationClickReceiver extends BroadcastReceiver {

    public static final String TAG = "NotificationClickReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        LogUtil.showLog(TAG,"通知栏点击");
        //获取栈顶的Activity
       // Activity currentActivity = ActivityManager.getCurrentActivity();
        intent = new Intent(Intent.ACTION_MAIN);
        intent.addCategory(Intent.CATEGORY_LAUNCHER);
        intent.setClass(context, MusicPlayerActivity.class);
        intent.putExtra("from","notify");
       // intent.putExtra("file",MyApplication.currentPlayMusic);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
        context.startActivity(intent);
    }
}

注意问题:

1.悬浮窗权限需动态申请。

2.通过bindService绑定播放,退出时Service也会退出,所以还要结合startService一起使用,在resume中startService即可进行后台播放。

3.通知栏点击跳转广播需静态注册:

<receiver android:name=".ui.musicplayer.NotificationClickReceiver" />

猜你喜欢

转载自blog.csdn.net/HuanWen_Cheng/article/details/132665449