精华内容
下载资源
问答
  • Android 音乐通知栏前言正文① 通知栏按钮点击监听② 通知栏点击监听③ 通知栏业务处理④ 运行效果图结语 前言   这篇文章的标题有些言简意赅了,也突出了这篇文章的核心,那就是通知栏的操作,你可以看到世面上的...

    前言

      这篇文章的标题有些言简意赅了,也突出了这篇文章的核心,那就是通知栏的操作,你可以看到世面上的音乐类APP都会有这个操作,通过音乐通知栏可以播放暂停、上一曲、下一曲、收藏、显示歌词等等。当然我这个Demo目前不考虑这么多,先实现播放暂停、上一曲、下一曲这些基本功能再说,你说对吧。

    正文

      在第四篇文章的到最后显示了通知栏,那么为什么我要把通知的的操作单独放到一篇文章来进行讲解呢?因为里面有很多业务逻辑,还有通信的关系,所以才这么做的。

    ① 通知栏按钮点击监听

      要实现具体的业务功能,首先要监听到点击事件,这一点是毋庸置疑的,谁赞成,谁反对。首先增加几个全局变量,打开Constant

    	/**
         * 歌曲播放
         */
        public static final String PLAY = "play";
        /**
         * 歌曲暂停
         */
        public static final String PAUSE = "pause";
        /**
         * 上一曲
         */
        public static final String PREV = "prev";
        /**
         * 下一曲
         */
        public static final String NEXT = "next";
        /**
         * 关闭通知栏
         */
        public static final String CLOSE = "close";
        /**
         * 进度变化
         */
        public static final String PROGRESS = "progress";
    

    这些都是用来表明当前歌曲的状态的,至关重要。之前我通过RemoteViews来指定一个布局文件,从而实现自定义通知栏样式的效果,那么对于通知栏页面的按钮的点击事件,也是交给RemoteViews来完成来的,下面进行实例化,把它变成成员变量。

    在Service中实例化

    private static RemoteViews remoteViews;
    

    然后单独写一个方法对RemoteViews进行初始化配置。

    	/**
         * 初始化自定义通知栏 的按钮点击事件
         */
        private void initRemoteViews() {
            remoteViews = new RemoteViews(this.getPackageName(), R.layout.notification);
    
            //通知栏控制器上一首按钮广播操作
            Intent intentPrev = new Intent(PREV);
            PendingIntent prevPendingIntent = PendingIntent.getBroadcast(this, 0, intentPrev, 0);
            //为prev控件注册事件
            remoteViews.setOnClickPendingIntent(R.id.btn_notification_previous, prevPendingIntent);
    
            //通知栏控制器播放暂停按钮广播操作  //用于接收广播时过滤意图信息
            Intent intentPlay = new Intent(PLAY);
            PendingIntent playPendingIntent = PendingIntent.getBroadcast(this, 0, intentPlay, 0);
            //为play控件注册事件
            remoteViews.setOnClickPendingIntent(R.id.btn_notification_play, playPendingIntent);
    
            //通知栏控制器下一首按钮广播操作
            Intent intentNext = new Intent(NEXT);
            PendingIntent nextPendingIntent = PendingIntent.getBroadcast(this, 0, intentNext, 0);
            //为next控件注册事件
            remoteViews.setOnClickPendingIntent(R.id.btn_notification_next, nextPendingIntent);
    
            //通知栏控制器关闭按钮广播操作
            Intent intentClose = new Intent(CLOSE);
            PendingIntent closePendingIntent = PendingIntent.getBroadcast(this, 0, intentClose, 0);
            //为close控件注册事件
            remoteViews.setOnClickPendingIntent(R.id.btn_notification_close, closePendingIntent);
    
        }
    

    目前通知栏上看到的按钮只有四个,因为播放和暂停是一个按钮,到时候可以根据MediaPlayer的播放状态做进一步的处理,上面四个按钮,点击之后会发送一个广播,既然有广播,那自然要有一个广播接收器,就好比,你到淘宝上买衣服,别人给你发货了,你总要设置一个收货地址吧。这是一个道理的。至于广播接收器,可以写在Service里面,作为一个内部类使用。那么先创建这个内部类。

    	/**
         * 广播接收器 (内部类)
         */
        public class MusicReceiver extends BroadcastReceiver {
    
            public static final String TAG = "MusicReceiver";
    
            @Override
            public void onReceive(Context context, Intent intent) {
            	//UI控制
                UIControl(intent.getAction(), TAG);
            }
        }
    

    然后来看看UIControl方法。

    	/**
         * 页面的UI 控制 ,通过服务来控制页面和通知栏的UI
         *
         * @param state 状态码
         * @param tag
         */
        private void UIControl(String state, String tag) {
            switch (state) {
                case PLAY:
                    BLog.d(tag,PLAY+" or "+PAUSE);
                    break;
                case PREV:
                    BLog.d(tag,PREV);
                    break;
                case NEXT:
                    BLog.d(tag,NEXT);
                    break;
                case CLOSE:
                    BLog.d(tag,CLOSE);
                    break;
                default:
                    break;
            }
        }
    

    对应四个通知栏的按钮,这是是作为广播的接收。但是要实际收到,还要注册才行。
    所以要注册动态广播。

    	/**
         * 注册动态广播
         */
        private void registerMusicReceiver() {
            musicReceiver = new MusicReceiver();
            IntentFilter intentFilter = new IntentFilter();
            intentFilter.addAction(PLAY);
            intentFilter.addAction(PREV);
            intentFilter.addAction(NEXT);
            intentFilter.addAction(CLOSE);
            registerReceiver(musicReceiver, intentFilter);
        }
    

    在这里你可以发现,我对四个值进行了拦截过滤,也就是说当我点击通知栏的上一曲按钮时,会发送动作名为PREV的广播,而这个时候MusicReceiver拦截到PREV的广播,传递给onReceive。然后在onReceive对不同的动作做不同的处理,目前我只是打印了日志而已。
    现在你可以将showNotification方法中的如下代码删除掉。

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

    然后在Service中的onCreate中调用。

    	@Override
        public void onCreate() {
            super.onCreate();
            
            
            initRemoteViews();
            //注册动态广播
            registerMusicReceiver();
    
    		showNotification();
    
            BLog.d(TAG, "onCreate");
        }
    
    

    initRemoteViews 方法一定要在 showNotification之前调用,否则你就等着null Object 然后APP崩溃吧。
    在服务销毁的时候要解绑广播接收者

    	@Override
        public void onDestroy() {
            super.onDestroy();
            if (musicReceiver != null) {
                //解除动态注册的广播
                unregisterReceiver(musicReceiver);
            }
        }
    

    下面运行一下,日志如下:
    在这里插入图片描述
    现在通知栏的按钮点击事件就已经监听到了,下面做通知栏的点击事件。

    ② 通知栏点击监听

      只要是通知栏按钮以外的点击都属于通知栏的点击,这个要区分开,别搞混了。在写代码要想清楚一点,当我们点击通知栏的时候,要进入那个页面,我仔细观察过其他音乐APP的这个点击通知栏的效果,是从那个页面切换到后台,下次点击通知栏时就进入到那个页面,也就是说它点击跳转的页面是动态的,所以不能是写死的。有了这个业务需求那么就可以开始写代码了。这里也是需要用到广播的,只不过不再是写内部类了。在com.llw.goodmusic下面新建一个receiver的包,然后创建NotificationClickReceiver,里面的两个可以不用勾选。
    在这里插入图片描述
    创建好之后,打开AndroidManifest.xml你会看到如下代码:

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

    下面进入MusicService中,

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

    然后通过.setContentIntent(pendingIntent)设置进去,如下图所示
    在这里插入图片描述

    下面进入到NotificationClickReceiver中。

    package com.llw.goodmusic.receiver;
    
    import android.app.Activity;
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import com.llw.goodmusic.utils.BLog;
    
    
    /**
     * 通知点击广播接收器  跳转到栈顶的Activity ,而不是new 一个新的Activity
     *
     * @author llw
     */
    public class NotificationClickReceiver extends BroadcastReceiver {
    
        public static final String TAG = "NotificationClickReceiver";
    
        @Override
        public void onReceive(Context context, Intent intent) {
    
            BLog.d(TAG,"通知栏点击");
    
        }
    }
    
    

    然后运行,运行之后点击通知栏,再看日志打印,如下所示:

    在这里插入图片描述

    ③ 通知栏业务处理

      在上面已经实现了通知栏的点击监听了,下面就要开始进行业务逻辑的处理了。先解决通知栏的点击业务处理,再解决通知栏按钮的点击处理,打开AndroidManager,注意这是之前我自己写的,不是系统的。在里面增加

    	/**
         * 弱引用
         */
        private static WeakReference<Activity> activityWeakReference;
    
        private static Object activityUpdateLock = new Object();
    
    	/**
         * 得到当前Activity
         * @return
         */
        public static Activity getCurrentActivity() {
            Activity currentActivity = null;
            synchronized (activityUpdateLock){
                if (activityWeakReference != null) {
                    currentActivity = activityWeakReference.get();
                }
            }
            return currentActivity;
        }
    
        /**
         * 设置当前Activity
         * @return
         */
        public static void setCurrentActivity(Activity activity) {
            synchronized (activityUpdateLock){
                activityWeakReference = new WeakReference<Activity>(activity);
            }
    
        }
    

    然后进入到BasicApplication中,在onCreate中写入:

    registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
                @Override
                public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
    
                }
    
                @Override
                public void onActivityStarted(Activity activity) {
    
                }
    
                @Override
                public void onActivityResumed(Activity activity) {
                    ActivityManager.setCurrentActivity(activity);
                }
    
                @Override
                public void onActivityPaused(Activity activity) {
    
                }
    
                @Override
                public void onActivityStopped(Activity activity) {
    
                }
    
                @Override
                public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
    
                }
    
                @Override
                public void onActivityDestroyed(Activity activity) {
    
                }
            });
    

    通过上面得代码就可以得到栈顶的Activity,那么怎么来使用这个Activity呢,进入到NotificationClickReceiver

    	@Override
        public void onReceive(Context context, Intent intent) {
    
            BLog.d(TAG,"通知栏点击");
    
            //获取栈顶的Activity
            Activity currentActivity = ActivityManager.getCurrentActivity();
            intent = new Intent(Intent.ACTION_MAIN);
            intent.addCategory(Intent.CATEGORY_LAUNCHER);
            intent.setClass(context, currentActivity.getClass());
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
            context.startActivity(intent);
        }
    

    这样就可以实现,点击通知栏时跳转到栈顶的Activity而不是新建一个Activity。
    下面就是针对通知栏的信息显示做处理了,首先肯定要根据不同的音乐显示不同的歌曲信息,这一点毋庸置疑。那么这样的话就不能一开始就显示通知栏了,而是在点击播放按钮的时候显示通知栏,当切歌,或者暂停时更新这个通知栏的状态,于是就可以在MusicService中写入一个这样的方法。

    	/**
         * 初始化通知
         */
        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, PendingIntent.FLAG_UPDATE_CURRENT);
    
            //初始化通知
            notification = new NotificationCompat.Builder(this, "play_control")
                    .setContentIntent(pendingIntent)
                    .setWhen(System.currentTimeMillis())
                    .setSmallIcon(R.mipmap.icon_big_logo)
                    .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.icon_big_logo))
                    .setCustomContentView(remoteViews)
                    .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
                    .setAutoCancel(false)
                    .setOnlyAlertOnce(true)
                    .setOngoing(true)
                    .build();
        }
    

    这里就是把原来的showNotification方法改了一下,把显示通知的代码放到改变通知栏状态的时候使用。当然还是要在onCreate中调用这个方法的。
    下面先在MusiceService中定义这些变量

    	/**
         * 歌曲间隔时间
         */
        private static final int INTERNAL_TIME = 1000;
    
        /**
         * 歌曲列表
         */
        private static List<Song> mList = new ArrayList<>();
    
        /**
         * 音乐播放器
         */
        public MediaPlayer mediaPlayer;
        /**
         * 记录播放的位置
         */
        int playPosition = 0;
    
        /**
         * 通知
         */
        private static Notification notification;
        /**
         * 通知栏视图
         */
        private static RemoteViews remoteViews;
        /**
         * 通知ID
         */
        private int NOTIFICATION_ID = 1;
        /**
         * 通知管理器
         */
        private static NotificationManager manager;
        /**
         * 音乐广播接收器
         */
        private MusicReceiver musicReceiver;
    

    然后写入一个更改通知栏样式的方法,每次对音乐进行控制时都会调用。

    	/**
         * 更改通知的信息和UI
         * @param position 歌曲位置
         */
        public void updateNotificationShow(int position) {
            //播放状态判断
            if (mediaPlayer.isPlaying()) {
                remoteViews.setImageViewResource(R.id.btn_notification_play, R.drawable.pause_black);
            } else {
                remoteViews.setImageViewResource(R.id.btn_notification_play, R.drawable.play_black);
            }
            //封面专辑
            remoteViews.setImageViewBitmap(R.id.iv_album_cover, MusicUtils.getAlbumPicture(this, mList.get(position).getPath(), 0));
            //歌曲名
            remoteViews.setTextViewText(R.id.tv_notification_song_name, mList.get(position).getSong());
            //歌手名
            remoteViews.setTextViewText(R.id.tv_notification_singer, mList.get(position).getSinger());
            //发送通知
            manager.notify(NOTIFICATION_ID, notification);
        }
    

    在这个方法里面我调用MusicUtils工具类的getAlbumPicture方法。这个方法我做了一点点改动
    改动如下图所示:
    在这里插入图片描述

    下面就是点击播放时的音乐方法了。

    	/**
         * 播放
         */
        public void play(int position) {
    
            if (mediaPlayer == null) {
                mediaPlayer = new MediaPlayer();
                //监听音乐播放完毕事件,自动下一曲
                mediaPlayer.setOnCompletionListener(this);
            }
            //播放时 获取当前歌曲列表是否有歌曲
    		mList = LitePal.findAll(Song.class);
            if (mList.size() <= 0) {
                return;
            }
    
            try {
                //切歌前先重置,释放掉之前的资源
                mediaPlayer.reset();
                playPosition = position;
                //设置播放音频的资源路径
                mediaPlayer.setDataSource(mList.get(position).path);
                mediaPlayer.prepare();
                mediaPlayer.start();
    
                //显示通知
                updateNotificationShow(position);
                
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    

      在上面的播放方法中,首先初始化了MediaPlayer,然后添加了播放完成的监听,这个在后面也是要实现的。然后获取当前的播放位置赋值给成员变量,之后通过位置得到歌曲的路径,通过路径来播放音乐,播放音乐之后将位置传递给显示通知栏的方法,此时通知栏的信息久会更改。

    在onCreate方法中添加如下代码,获取本地歌曲数据。

    mList = LitePal.findAll(Song.class);
    

    这样做是避免空对象导致APP的崩溃。

    接下来就是上一曲的方法

    	/**
         * 上一首
         */
        public void previousMusic() {
            if (playPosition <= 0) {
                playPosition = mList.size() - 1;
            } else {
                playPosition -= 1;
            }
            play(playPosition);
        }
    

    通过播放位置,先判断当前是为第一首歌,是则将播放位置移动到最后一首,不是则直接减一,之后则调用play方法播放上一首歌曲。

    下一曲的方法

    	/**
         * 下一首
         */
        public void nextMusic() {
            if (playPosition >= mList.size() - 1) {
                playPosition = 0;
            } else {
                playPosition += 1;
            }
            play(playPosition);
        }
    

    先判断当前是否为最后一首,是的话则从移动到第一首,不是则加一到下一首。然后调用play方法播放下一首歌曲。

    暂停继续音乐

    	/**
         * 暂停/继续 音乐
         */
        public void pauseOrContinueMusic() {
            if (mediaPlayer.isPlaying()) {
                mediaPlayer.pause();
            } else {
                mediaPlayer.start();
            }
            //更改通知栏播放状态
            updateNotificationShow(playPosition);
        }
    

    更改播放状态

    最后是关闭通知栏的方法

    	/**
         * 关闭音乐通知栏
         */
        public void closeNotification() {
            if (mediaPlayer != null) {
                if (mediaPlayer.isPlaying()) {
                    mediaPlayer.pause();
                }
            }
            manager.cancel(NOTIFICATION_ID);
        }
    

    下面就是调用的地方了
    在这里插入图片描述
    然后还要实现MediaPlayer的音乐播放完成的监听,

    public class MusicService extends Service implements MediaPlayer.OnCompletionListener
    

    然后重写onCompletion方法,在里面直接调用nextMusic播放下一曲即可。

    	/**
         * 当前音乐播放完成监听
         *
         * @param mp
         */
        @Override
        public void onCompletion(MediaPlayer mp) {
            //下一曲
            nextMusic();
        }
    

    下面就要设置通知出现的入口,一般来说是在点击播放按钮,当前有音乐播放时,才会显示通知。然后在layout下面新建一个通用的底部通知布局。
    play_control_layout.xml

    <?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools">
    
        <!--底部播放控制布局-->
        <LinearLayout
            android:id="@+id/lay_bottom"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:background="@color/bottom_bg_color"
            android:gravity="center_vertical"
            android:paddingLeft="@dimen/dp_8"
            android:paddingTop="@dimen/dp_8"
            android:paddingRight="@dimen/dp_16"
            android:paddingBottom="@dimen/dp_8">
    
            <!-- logo和播放进度 使用相对布局达成覆盖的效果-->
            <RelativeLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content">
                <!--logo-->
                <com.google.android.material.imageview.ShapeableImageView
                    android:id="@+id/iv_logo"
                    android:layout_width="@dimen/dp_48"
                    android:layout_height="@dimen/dp_48"
                    android:padding="1dp"
                    android:src="@mipmap/icon_music"
                    app:shapeAppearanceOverlay="@style/circleImageStyle"
                    app:strokeColor="@color/white"
                    app:strokeWidth="@dimen/dp_2" />
                <!--播放进度  自定义View-->
                <com.llw.goodmusic.view.MusicRoundProgressView
                    android:id="@+id/music_progress"
                    android:layout_width="@dimen/dp_48"
                    android:layout_height="@dimen/dp_48"
                    app:radius="22dp"
                    app:strokeColor="@color/gold_color"
                    app:strokeWidth="2dp" />
            </RelativeLayout>
    
            <!--歌曲信息  歌名 - 歌手 -->
            <com.google.android.material.textview.MaterialTextView
                android:id="@+id/tv_song_name"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:ellipsize="marquee"
                android:focusable="true"
                android:focusableInTouchMode="true"
                android:marqueeRepeatLimit="marquee_forever"
                android:paddingLeft="@dimen/dp_12"
                android:paddingRight="@dimen/dp_12"
                android:singleLine="true"
                android:text="Good Music"
                android:textColor="@color/white"
                android:textSize="@dimen/sp_16" />
            <!--歌曲控制按钮-->
            <com.google.android.material.button.MaterialButton
                android:id="@+id/btn_play"
                android:layout_width="@dimen/dp_36"
                android:layout_height="@dimen/dp_36"
                android:insetLeft="@dimen/dp_0"
                android:insetTop="@dimen/dp_0"
                android:insetRight="@dimen/dp_0"
                android:insetBottom="@dimen/dp_0"
                android:theme="@style/Theme.MaterialComponents.Light.NoActionBar"
                app:backgroundTint="@color/transparent"
                app:cornerRadius="@dimen/dp_18"
                app:icon="@mipmap/icon_play"
                app:iconGravity="textStart"
                app:iconPadding="@dimen/dp_0"
                app:iconSize="@dimen/dp_36" />
        </LinearLayout>
    </layout>
    
    

    其实就是之前LocalMusicActivity的底部布局。

    在这里插入图片描述
    下面进入MainActivity中,

    	/**
         * 底部logo图标,点击之后弹出当前播放歌曲详情页
         */
        private ShapeableImageView ivLogo;
        /**
         * 底部当前播放歌名
         */
        private MaterialTextView tvSongName;
        /**
         * 底部当前歌曲控制按钮, 播放和暂停
         */
        private MaterialButton btnPlay;
        /**
         * 自定义进度条
         */
        private MusicRoundProgressView musicProgress;
        /**
         * 列表位置
         */
        private int listPosition = 0;
    

    然后在initData中,通过引入的布局绑定控件,并且添加点击监听,下面就可以在
    在这里插入图片描述

    	@Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.lay_local_music:
                    //本地音乐
                    startActivity(new Intent(context, LocalMusicActivity.class));
                    break;
                case R.id.btn_play:
                    if (mList.size() == 0) {
                        show("没有可播放的音乐,请到 “本地音乐” 进行扫描");
                        return;
                    }
    
                    musicService.play(listPosition);
    
                    break;
                default:
                    break;
            }
        }
    

    下面运行测试一波:

    ④ 运行效果图

    在这里插入图片描述

    结语

      现在已经搞定了后台播放和通知栏控制音乐,下一篇就该是通知栏和Activity的双向控制了。

    源码地址:Good Music

    展开全文
  • android音乐通知通知栏

    千次阅读 2019-11-02 08:40:33
    我们以音乐播放器为例子做一个通知到通知栏(并且我们要求点击按钮切换通知栏按钮状态并做切歌的操作) 我们先写一个广播 public class XMPlayerReceiver extends BroadcastReceiver { public static final ...

    我们以音乐播放器为例子做一个通知到 通知栏(并且我们要求点击按钮切换通知栏按钮状态并做切歌的操作)
    我们先写一个广播

    public class XMPlayerReceiver extends BroadcastReceiver {
        public static final String PLAY_PRE = "play_pre";
        public static final String PLAY_NEXT = "play_next";
        public static final String PLAY_PAUSE = "play_pause";
        public static final String PLAY_PLAY = "play_play";
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(PLAY_NEXT)){//PLAY_NEXT
                Log.e("XMPlayerReceiver", "通知栏点击了下一首");
            }
            if (intent.getAction().equals(PLAY_PRE)) {;
                Log.e("XMPlayerReceiver", "通知栏点击了上一首");
            }
            if (intent.getAction().equals(PLAY_PAUSE)) {
                Log.e("XMPlayerReceiver", "通知栏点击了暂停");
            }
            if (intent.getAction().equals(PLAY_PLAY)) {
                Log.e("XMPlayerReceiver", "通知栏点击了开始");
            }
        }
    }

    AndroidManifest.xml中注册上我们写的广播

            <receiver
                android:name=".app.audioheler.ability.XMPlayerReceiver"
                android:exported="true"
                android:process=":player">
                <intent-filter>
                    <action android:name="play_pre" />
                    <action android:name="play_next" />
                    <action android:name="play_pause" />
                    <action android:name="play_play" />
                </intent-filter>
            </receiver>

    准备好广播之后我们发一个推送到通知栏。

    先自定义一个RemoteViews ,xml自己写

    private RemoteViews initNotifyView(Bitmap bitmap) {
            String packageName = context.getPackageName();
            RemoteViews remoteView = new RemoteViews(packageName, R.layout.你的xml);
            remoteView.setImageViewBitmap(R.id.xml中放图的imageview id, Bitmap位图);
            remoteView.setTextViewText(R.id.xml中标题的id, "标题内容");
            remoteView.setTextViewText(R.id.xml中小标题的id, "小标题内容");
    
            Intent prv = new Intent(context,XMPlayerReceiver.class);//播放上一首
            prv.setAction(PLAY_PRE);
            PendingIntent intent_prev = PendingIntent.getBroadcast(context, 1, prv,
                    PendingIntent.FLAG_UPDATE_CURRENT);
            remoteView.setOnClickPendingIntent(R.id.上一首按钮的id, intent_prev);
    
    
            Intent next = new Intent(context,XMPlayerReceiver.class);//播放下一首
            next.setAction(PLAY_NEXT);
            PendingIntent intent_next = PendingIntent.getBroadcast(context, 2, next,
                    PendingIntent.FLAG_UPDATE_CURRENT);
            remoteView.setOnClickPendingIntent(R.id.下一首按钮的id, intent_next);
    
    
            Intent startpause = new Intent(context,XMPlayerReceiver.class);//暂停
            startpause.setAction(PLAY_PAUSE);
            PendingIntent intent_pause = PendingIntent.getBroadcast(context, 3, startpause,
                    PendingIntent.FLAG_UPDATE_CURRENT);
            remoteView.setOnClickPendingIntent(R.id.暂停按钮的id, intent_pause);
    
            Intent startplay = new Intent(context,XMPlayerReceiver.class);//播放
            startplay.setAction(PLAY_PLAY);
            PendingIntent intent_play = PendingIntent.getBroadcast(context, 4, startplay,
                    PendingIntent.FLAG_UPDATE_CURRENT);
            remoteView.setOnClickPendingIntent(R.id.播放按钮的id, intent_play);
            return remoteView;
        }

    现在把自定义的样式发到通知栏上

    NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
        String channelId = "notification";
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {//适配一下高版本
            NotificationChannel channel = new NotificationChannel(channelId,
                    "listen",
                    NotificationManager.IMPORTANCE_DEFAULT);
            channel.enableLights(false); //是否在桌面icon展示小红点
            channel.setLightColor(Color.RED); //小红点颜色
            channel.setSound(null, null);//关了通知默认提示音
            channel.setShowBadge(false); //是否在久按桌面图标时显示此渠道的通知
            notificationManager.createNotificationChannel(channel);
        }
        NotificationCompat.Builder builder = new NotificationCompat.Builder(context, channelId)
                .setSmallIcon(R.mipmap.ic_launcher)//这玩意在通知栏上显示一个logo
                .setCategory(CATEGORY_MESSAGE)
                .setDefaults(DEFAULT_ALL)
                .setOngoing(true);
        //点击通知栏跳转的activity
        Intent intent = new Intent(context, NotifyActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent,
        PendingIntent.FLAG_UPDATE_CURRENT);
        builder.setAutoCancel(false);//点击不让消失
        builder.setSound(null);//关了通知默认提示音
        builder.setPriority(PRIORITY_MAX);//咱们通知很重要
        builder.setVibrate(null);//关了车震
        builder.setContentIntent(pendingIntent);//整个点击跳转activity安排上
        builder.setOnlyAlertOnce(false);
        RemoteViews remoteViews = initNotifyView(bitmap);
        builder.setContent(remoteViews);//把自定义view放上
        builder.setCustomBigContentView(remoteViews);//把自定义view放上
        Notification notification = builder.build();
        notification.flags |= FLAG_ONGOING_EVENT;
        notification.flags |= Notification.FLAG_NO_CLEAR;//不让手动清除 通知栏常驻
        notification.sound = null;//关了通知默认提示音
        notificationManager.notify(notifyId, notification);

    需要的时候调用上段代码将通知发到通知栏上  在BroadcastReceiver 中接收点击事件。若更新通知栏的样式,重新创建RemoteViews再发一遍通知好了  notifyId使用同一个。

    当我们不需要这个通知栏播放器时  直接关闭通知

    notificationManager.cancel(notifyId);

    这俩biang玩意别跟别的app重了  带上自己包名

     

    如有不重发通知更新通知栏的方法请告诉我

     

    展开全文
  • 通知栏安卓音乐播放器

    热门讨论 2014-08-11 10:55:52
    实现了类似天天动听的通知栏管理音乐功能,有上一首、下一首、播放、暂停、关闭应用,实现中用到了IntentService、BroadcastReceiver、Application、Notification等,对安卓进阶很有帮助,当然项目只是个demo,还有...
  • Android 音乐播放器的通知栏

    千次阅读 2017-10-05 11:52:03
    Android音乐播放器的通知栏效果说明 我点击×按钮会关闭通知栏和应用, 点击停止按钮会在界面显示停止并且这个按钮的图片换成播放图片,再点击一次界面显示播放,且图片换回来 点击上一首和下一首按钮会在界面上...

    Android音乐播放器的通知栏

    效果说明
    我点击×按钮会关闭通知栏和应用,
    点击停止按钮会在界面显示停止并且这个按钮的图片换成播放图片,再点击一次界面显示播放,且图片换回来
    点击上一首和下一首按钮会在界面上分别显示上一首和下一首的字符串。

    制作过程

    首先我先贴一些关键代码,源码地址最后给出

    public class MainActivity extends AppCompatActivity {
    
        private static final int NOTIFICATION_ID = 1; // 如果id设置为0,会导致不能设置为前台service
        public static NotificationManager manager;
        RemoteViews remoteViews;
        Notification notification;
        private Button btn;
        private TextView tv;
        static MainActivity appCompatActivity;
        int state = 0;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            if(appCompatActivity == null){
                appCompatActivity = this;
            }
    
            btn = (Button)findViewById(R.id.btn);
            tv = (TextView)findViewById(R.id.tv);
    
            btn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    createNotifcation();
                }
            });
    
        }
    
        public void createNotifcation(){
            notification = new Notification();
            notification.icon =R.drawable.musicfile;
            notification.tickerText = "title";
            notification.when = System.currentTimeMillis();
            notification.flags = Notification.FLAG_AUTO_CANCEL;
            remoteViews = new RemoteViews(getPackageName(),
                    R.layout.widget);
            remoteViews.setTextViewText(R.id.wt_title, "title");
            remoteViews.setImageViewResource(R.id.icon1, R.drawable.musicfile);
            if(state == 0){
                remoteViews.setImageViewResource(R.id.wt_play,R.drawable.pause);
            }else {
                remoteViews.setImageViewResource(R.id.wt_play,R.drawable.play);
            }
    
            Intent previous=new Intent("com.example.broadcasttest.PREVIOUS");
            PendingIntent pi_previous = PendingIntent.getBroadcast(MainActivity.this,0,
                    previous,PendingIntent.FLAG_UPDATE_CURRENT);
            remoteViews.setOnClickPendingIntent(R.id.wt_previous,pi_previous);
    
    
            Intent play=new Intent("com.example.broadcasttest.PLAY");
            PendingIntent pi_play = PendingIntent.getBroadcast(MainActivity.this,0,
                    play,PendingIntent.FLAG_UPDATE_CURRENT);
            remoteViews.setOnClickPendingIntent(R.id.wt_play,pi_play);
    
            Intent next=new Intent("com.example.broadcasttest.NEXT");
            PendingIntent pi_next = PendingIntent.getBroadcast(MainActivity.this,0,
                    next,PendingIntent.FLAG_UPDATE_CURRENT);
            remoteViews.setOnClickPendingIntent(R.id.wt_next,pi_next);
    
            Intent clear=new Intent("com.example.broadcasttest.CLEAR");
            PendingIntent pi_clear = PendingIntent.getBroadcast(MainActivity.this,0,
                    clear,PendingIntent.FLAG_UPDATE_CURRENT);
            remoteViews.setOnClickPendingIntent(R.id.wt_clear,pi_clear);
    
            notification.contentView = remoteViews;
            manager = (NotificationManager) getSystemService(
                    Context.NOTIFICATION_SERVICE);
    
            manager.notify(NOTIFICATION_ID,notification);
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            if(manager != null ){
                manager.cancel(NOTIFICATION_ID);
            }
        }
    
        public static MainActivity getInstance(){
    
            return appCompatActivity;
        }
    
        public void nextMusic(){
            tv.setText("下一首");
        }
    
        public void playMusic(){
    
            if(state == 0){
                tv.setText("播放");
                state =1;
            }else {
                tv.setText("暂停");
                state = 0;
            }
    
            createNotifcation();
    
    
        }
        public void previousMusic(){
            tv.setText("上一首");
        }
    
        public void clearMusic(){
            finish();
        }
    }

    然后是广播的代码,我就贴出一个,其他的广播都一个样

    public class NextBroadcastReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent){
            final MainActivity musicActivity = MainActivity.getInstance();
            musicActivity.runOnUiThread(new Runnable() {
    
                @Override
                public void run() {
                    musicActivity.nextMusic();
                }
            });
    
        }
    }
    

    我们可以看到我们使用RemoteView来做通知栏,因为这样可以制作自定义通知栏,并且能够给控件设置点击事件,而且还能改变控件的一些属性,比如图片和字符串之类的,但是我们需要注意我们只能改变TextView和ImageView的样式。

    还有就是这个点击事件我是通过广播来实现,广播通过获取activity的实例来改变activity的界面

    然后我们在onDestroy()设置取消通知栏,以防出现Force Close

    其实可以用service来管理通知栏,但是我有点懒,大家可以自己去改改,不懂的来问

    最后源代码地址
    979451341/MusicNotification: 音乐播放器的通知栏
    https://github.com/979451341/MusicNotification

    展开全文
  • Android基本操作之音乐播放器的部署(含通知栏操作、notification、service、获取本地音乐列表)
  • 最近在做一个音乐播放器的时候遇到了一个关于notification的问题,在网上找了很久都没有头绪。后来研究了一下午,终于找到了解决的办法。 问题描述首先请看网易云音乐通知栏

    最近在做一个音乐播放器的时候遇到了一个关于notification的问题,在网上找了很久都没有头绪。后来找到了解决的办法,特意记录一下。

    问题描述

    首先请看网易云音乐的通知栏
    普通高度的notification.png
    加高notification.png

    可以看到,网易云音乐的通知栏有两种,一种是普通的通知栏,一种是显示bigView的通知栏。这两种通知栏是可以通过双指上滑/下滑来切换的(说实话,我今天才知道原来还有这个功能…)。

    网易云音乐在播放音乐的时候,默认显示的是第二种通知栏,而我今天遇到的问题是:通过自定义布局来实现通知栏,默认情况下只能显示第一种普通高度的通知栏,需要双指滑动一下才能显示bigView通知栏。

    对于大多数用户来说,可能并不知道有双指滑动通知栏这一功能,因此这样的用户体验是不够友好的,那么,如何实现像网易云一样的,默认就显示bigView的notification呢?

    首先新建一个测试项目,再新建两个布局,一个用作普通的notification视图,一个用作bigView的notification视图:

    1. 普通notification视图,命名为normal_notification.xml
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
    
        <ImageView
            android:layout_width="64dp"
            android:layout_height="64dp"
            android:src="@mipmap/icon"/>
    
        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="64dp"
            android:layout_marginEnd="10dp"
            android:layout_marginStart="10dp"
            android:layout_weight="1"
            android:orientation="vertical">
    
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="10dp"
                android:text="歌曲名"
                android:textSize="18sp"/>
    
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="5dp"
                android:text="歌手名"/>
        </LinearLayout>
    
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="64dp"
            android:gravity="center_vertical">
            <ImageButton
                android:layout_width="26dp"
                android:layout_height="26dp"
                android:background="@null"
                android:scaleType="fitCenter"
                android:src="@mipmap/pre"/>
    
            <ImageButton
                android:layout_marginStart="10dp"
                android:layout_width="26dp"
                android:layout_height="26dp"
                android:background="@null"
                android:scaleType="fitCenter"
                android:src="@mipmap/play"/>
    
            <ImageButton
                android:layout_marginStart="10dp"
                android:layout_width="26dp"
                android:layout_height="26dp"
                android:background="@null"
                android:scaleType="fitCenter"
                android:src="@mipmap/next"/>
        </LinearLayout>
    
    </LinearLayout>

    2.bigView的notification视图,命名为big_notification.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
    
        <ImageView
            android:layout_width="110dp"
            android:layout_height="110dp"
            android:src="@mipmap/icon"/>
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="110dp"
            android:orientation="vertical">
    
            <TextView
                android:id="@+id/tv_song_name"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginEnd="10dp"
                android:layout_marginStart="10dp"
                android:layout_marginTop="10dp"
                android:text="歌名"
                android:textSize="15sp"/>
    
            <TextView
                android:id="@+id/tv_song_singer"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginEnd="10dp"
                android:layout_marginStart="10dp"
                android:layout_marginTop="5dp"
                android:text="歌名"
                android:textSize="12sp"/>
    
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginStart="10dp"
                android:layout_marginTop="20dp"
                android:gravity="center_vertical"
                android:orientation="horizontal">
    
                <ImageButton
                    android:layout_marginEnd="10dp"
                    android:layout_width="26dp"
                    android:layout_height="26dp"
                    android:background="@null"
                    android:scaleType="fitCenter"
                    android:src="@mipmap/like"/>
    
                <ImageButton
                    android:layout_marginEnd="10dp"
                    android:layout_width="26dp"
                    android:layout_height="26dp"
                    android:background="@null"
                    android:scaleType="fitCenter"
                    android:src="@mipmap/pre"/>
    
                <ImageButton
                    android:layout_marginEnd="10dp"
                    android:layout_width="38dp"
                    android:layout_height="38dp"
                    android:background="@null"
                    android:scaleType="fitCenter"
                    android:src="@mipmap/play"/>
    
                <ImageButton
                    android:layout_marginEnd="10dp"
                    android:layout_width="26dp"
                    android:layout_height="26dp"
                    android:background="@null"
                    android:scaleType="fitCenter"
                    android:src="@mipmap/next"/>
    
            </LinearLayout>
        </LinearLayout>
    </LinearLayout>

    除了这两个用作notification的布局文件之外,在主界面中还有一个按钮,通过按钮的点击事件,模拟开始播放音乐,发送通知。这里就不贴代码了,直接贴按钮点击事件中的核心代码:

    //发送自定义视图通知
    public void sendCustomViewNotification(View view) {
        //普通notification用到的视图
        RemoteViews normalView = new RemoteViews(getPackageName(), R.layout.normal_notification);
        //显示bigView的notification用到的视图
        RemoteViews bigView = new RemoteViews(getPackageName(), R.layout.big_notification);
    
        Notification notification = new NotificationCompat.Builder(this)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setTicker("开始播放啦~~")
                .setOngoing(true)
                .setContent(normalView)//设置普通notification视图
                .setCustomBigContentView(bigView)//设置显示bigView的notification视图  
                .setPriority(NotificationCompat.PRIORITY_MAX)//设置最大优先级
                .build();
    
        NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        manager.notify(22, notification);
        }

    上面这段代码相信大家应该经常使用,这是构建一个自定义通知的基本代码。在使用builder对象为notification设置一些列熟悉的时候,有三个关键的方法,我都已经注释出来了

    1.setContent:给notification设置普通状态下显示的视图
    2. setCustomBigContentView():给notification设置bigView

    再设置完上面两个方法之后,程序应该能实现双指滑动切换普通notification和bigView notification了,但还无法像网易云的通知栏一样,默认显示bigView notification,所以:

        3. setPriority(NotificationCompat.PRIORITY_MAX):给notification设置最高的优先级

    设置了优先级之后,终于能够实现和网易云音乐相同的通知栏效果了,大功告成,下面上图:

    默认启动的时候:

    默认启动时显示的通知栏

    双指滑动后效果:

    2.png

    PS:
    1.上面写的两个布局文件没有参考意义,快下班了,噼里啪啦写出来的,估计有些问题
    2.有空录下GIF,效果应该会更直观;
    3.如果看不到图了,请到http://www.jianshu.com/p/77da5abd3870查看

    展开全文
  • 问题描述首先请看网易云音乐通知栏普通高度的notification.png加高notification.png可以看到,网易云音乐通知栏有两种,一种是普通的通知栏,一种是显示bigView的通知栏。这两种通知栏是可以通过双指上滑/下滑来...
  • 音乐播放器消息通知栏切歌栏效果(Notification BroadcastReceiver).zip,太多无法一一验证是否可用,程序如果跑不起来需要自调,部分代码功能进行参考学习。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 8,915
精华内容 3,566
关键字:

安卓音乐通知栏