Android 音乐播放器的开发教程(十)通知栏Notification的使用 ----- 小达

时间:2021-08-05 10:15:59

通知栏Notification的使用

        在这一片博客中,小达将自己学习Notification的一些想法和大家分享一哈,学的不是很深,所有有些东西可能解释的不是特别到位,还请各位谅解哈Android 音乐播放器的开发教程(十)通知栏Notification的使用 ----- 小达.所谓Notification即 通知,是一种让你的应用程序在不使用Activity的情况下警示用户。它是看不见的程序组件(Broadcast Receiver,Service和不活跃的Activity) 警示用户有需要注意的事件发生的最好途径。后面的一大段一大段是接着前面的项目在继续,大家可以选择性的看一看.

        Notification 是由NotificationManager(系统服务)统一管理的。挂在下拉通知栏上面,就像下图所示,
Android 音乐播放器的开发教程(十)通知栏Notification的使用 ----- 小达
       上面显示的都是所谓的Notification,今天我们就来一步步的创建,添加按钮响应,再将Notification和我们的播放器联系起来,话不多说,现在就开始咯.
       
       先给Notification创建了个单独的布局文件,当notification被激活的时候,就在通知栏上面显示这个布局文件的样式,

notification_layout.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/notification_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_photo_01">

<ImageView //显示歌手头像的,,,,,基本没怎么用上,专辑图片不知道怎么弄得出不来
android:id="@+id/notification_artist_image"
android:layout_width="64.0dip"
android:layout_height="64.0dip"
android:background="#00000000"/>

<TextView //在通知栏上显示音乐名称的TextView
android:id="@+id/notification_music_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginLeft="5dp"
android:layout_marginStart="5.0dp"
android:layout_toRightOf="@+id/notification_artist_image"
android:layout_toEndOf="@+id/notification_artist_image"
android:focusable="true"
android:textColor="#FFADABFF"
android:textSize="18sp"
/>
<TextView<span style="font-family: Arial, Helvetica, sans-serif;"> //在通知栏上显示歌手的TextView</span>
android:id="@+id/notification_music_Artist"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/notification_music_title"
android:layout_alignStart="@+id/notification_music_title"
android:layout_marginTop="5.0dip"
android:layout_below="@id/notification_music_title"
android:textColor="#FFADABFF"
/>

<ImageButton //通知栏上的退出按钮
android:id="@+id/notification_exit_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/notification_exit"
android:layout_below="@+id/notification_music_title"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true" />

<ImageButton
android:id="@+id/notification_next_song_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/next_music_photo"
android:layout_toLeftOf="@+id/notification_exit_button"
android:layout_toStartOf="@+id/notification_exit_button"
/>

<ImageButton
android:id="@+id/notification_play_button"
android:layout_toLeftOf="@id/notification_next_song_button"
android:layout_toStartOf="@id/notification_next_song_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#00000000"/>

<ImageButton
android:id="@+id/notification_previous_song_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toLeftOf="@id/notification_play_button"
android:layout_toStartOf="@id/notification_play_button"
android:background="@drawable/previous_music_photo"
/>



</RelativeLayout>

       布局文件大致弄好了后,就在播放歌曲的同时,直接将这个布局文件显示到通知栏上去,这一步需要Notification和NotificationManager,小达这里是将notification放在了service里面进行操作了,其他地方也可以的,这是service里面的一部分代码,后面会有整个service的代码的,:
private void initMyNotification() {


        /*
        第一个参数是显示在通知栏上的小图标的图片
        第二个参数是在启动notification时,在状态栏上滚动的一句话
        第三个参数是在状态栏上显示的时间
         */
        myNotification = new Notification(R.drawable.notification_artist_default_image, "小卷毛音乐", System.currentTimeMillis());


        /*
        NotificationManager用来管理notification的显示和消失等
         */
        myNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);


        /*
        对刚才创建的一个notification实例设置各种参数
        其中的一个参数是flags
        这个参数可以设置该notification是何种状态
        这里设置的是ONGOING,表示这个notification会一直呆在通知栏上面
        也可以设置滑动后就消失的样式,看个人的不同需求
         */
        myNotification.flags = Notification.FLAG_ONGOING_EVENT;


        /*
        在我们创建的notification中有一个View子类的实例
        下面创建了一个RemoteViews的实例
        并且配置好各种显示的信息后
        将该实例传给notification
        往后面看会有一句
        myNotification.contentView = contentViews;
        这个就是传递实例了


         */
        RemoteViews contentViews = new RemoteViews(getPackageName(), R.layout.notification_layout);
        contentViews.setImageViewResource
                (R.id.notification_artist_image, R.drawable.notification_artist_default_image);


        if(mediaPlayer.isPlaying()){
            contentViews.setImageViewResource(R.id.notification_play_button,R.drawable.play_photo);
        }
        else{
            contentViews.setImageViewResource(R.id.notification_play_button,R.drawable.pause_photo);
        }




        /*
        将处理好了的一个View传给notification
        让其在通知栏上显示
         */
        myNotification.contentView = contentViews;        /*        在创建的notification中还有一个intent        Intent :意图,即告诉系统我要干什么,然后系统根据这个Intent做对应的事。        如startActivity相当于发送消息,而Intent是消息的内容。        PendingIntent :包装Intent,Intent 是我们直接使用 startActivity , startService 或 sendBroadcast 启动某项工作的意图。        而某些时候,我们并不能直接调用startActivity , startServide 或 sendBroadcast ,而是当程序或系统达到某一条件才发送Intent。        如这里的Notification,当用户点击Notification之后,由系统发出一条Activity 的 Intent 。        因此如果我们不用某种方法来告诉系统的话,系统是不知道是使用 startActivity ,startService 还是 sendBroadcast 来启动Intent 的(当然还有其他的“描述”),        因此这里便需要PendingIntent。        PendingIntent.getActivity的参数依次为:Context,发送者的请求码(可以填0),用于系统发送的Intent,标志位         */
</pre><pre name="code" class="java">        Intent notificationIntent = new Intent(this, MainActivity.class);        PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);        myNotification.contentIntent = contentIntent;        /*        用notificationManager来启动notification        通过调用notify这个函数来启动         */
        myNotificationManager.notify(0, myNotification);    }
</pre></div><div style="text-align:left"><span style="font-size:14px"></span></div><div style="text-align:left"><span style="font-size:14px">        这个函数是一个自定义的初始化函数,需要显示notification的时候直接调用就可以了,里面的注释还是比较详细的,有什么看不懂的地方可以给我留言.</span></div><p></p><p><span style="font-size:14px">        上面显示出来的Notification只能看,上面有几个按钮还不能点击,在这个上面的按钮点击监听器和普通的有点区别,由于notification经常和activity独立的存在,没有什么直接的关联,需要通过broadcast机制来互相传递信息,notification上的按钮点击之后,会发送一个指定了的广播,只需要接收后再做处理,就能达到按钮监听器的效果了,在notification上面按钮点击需要简单的三个步骤:</span></p><p><span style="font-size:14px">         第一步:          实例化一个intent,作为发送广播的intent,里面存放action,也就是需要传递给activity或者service的提示信息.</span></p><p><span style="font-size:14px"></span><pre name="code" class="java">        Intent previousButtonIntent = new Intent(NotificationMsg.NOTIFICATION_PREVIOUS_MUSIC);
      

         第二步:          实例化一个PendingIntent,把上面的intent包装起来,并说明是用来发广播的intent,

 

        PendingIntent pendPreviousButtonIntent = PendingIntent.getBroadcast(this, 0, previousButtonIntent, 0);


         第三步:          都猜中了把,就是将pendingIntent和notification上的按钮联系起来

        contentViews.setOnClickPendingIntent(R.id.notification_previous_song_button, pendPreviousButtonIntent);

         有没有很快,,,,这样点击之后就可以发送一个广播出去了,再怎么接受纯属个人喜好问题了哈.....

          下面是service的源码,好像有点长额,重点看红色的地方,是关于notification的:

package com.example.dada.myapplication;


import android.app.Notification;
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.media.MediaPlayer;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.view.animation.AnimationUtils;
import android.widget.RemoteViews;


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




public class PlayerService extends Service implements AppConstant {


    private int current_position;


    private String musicPath;
    private String music_artist;
    private String music_title;
<span style="color:#ff0000;">    private String notification_msg;</span>


    private boolean isPause = true;
    private boolean isChangToNext;


<span style="color:#ff0000;">    private NotificationManager myNotificationManager;                     //通知栏
    private Notification myNotification;</span>


    private ChangeToNextReceiver changeToNextReceiver;


    private PlayReceiver playReceiver;


    private ProgressChangeReceiver progressChangeReceiver;


    public static MediaPlayer mediaPlayer = new MediaPlayer();


    private Intent intent_to_activity = new Intent("com.example.communication.RECEIVER");
    private Intent intent_to_progressBar = new Intent("com.example.communication.BAR");
<span style="color:#ff0000;">    private Intent notification_to_activity = new Intent("com.example.communication.NOTIFICATION_TO_ACTIVITY");</span>


    private Handler myHandler = new Handler() {


        public void handleMessage(Message msg) {
            if (msg.what == PlayerMsg.PLAY_MSG) {
                current_position = mediaPlayer.getCurrentPosition();
                intent_to_progressBar.putExtra("position",  current_position);
                sendBroadcast(intent_to_progressBar);
                myHandler.sendEmptyMessageDelayed(PlayerMsg.PLAY_MSG, 1000);
            }
            if (msg.what == PlayerMsg.PAUSE) {
                stopMusic();
            }
        }
    };


    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }


    public int onStartCommand(Intent intent, int flags, int startId) {


        notification_msg = null;


        playReceiver = new PlayReceiver();
        changeToNextReceiver = new ChangeToNextReceiver();
        progressChangeReceiver = new ProgressChangeReceiver();
        IntentFilter intentChangeFilter = new IntentFilter();
        IntentFilter intentPlayFilter = new IntentFilter();
        IntentFilter intentProgressChangeFilter = new IntentFilter();
        intentChangeFilter.addAction("com.example.communication.ChANGE_MUSIC");
        intentPlayFilter.addAction("com.example.communication.PLAY");
        intentProgressChangeFilter.addAction("com.example.communication.PROGRESS_BAR");

<span style="color:#ff0000;">
        IntentFilter previousMusicFilter = new IntentFilter();
        previousMusicFilter.addAction(NotificationMsg.NOTIFICATION_PREVIOUS_MUSIC);
        registerReceiver(onClickReceiver, previousMusicFilter);

        IntentFilter nextMusicFilter = new IntentFilter();
        nextMusicFilter.addAction(NotificationMsg.NOTIFICATION_NEXT_MUSIC);
        registerReceiver(onClickReceiver,nextMusicFilter);

        IntentFilter pauseMusicFilter = new IntentFilter();
        pauseMusicFilter.addAction(NotificationMsg.NOTIFICATION_PAUSE_MUSIC);
        registerReceiver(onClickReceiver,pauseMusicFilter);

        IntentFilter exitFilter = new IntentFilter();
        exitFilter.addAction(NotificationMsg.NOTIFICATION_EXIT);
        registerReceiver(onClickReceiver,exitFilter);</span>

<span style="color:#ff0000;">        registerReceiver(playReceiver, intentPlayFilter);
        registerReceiver(changeToNextReceiver, intentChangeFilter);
        registerReceiver(progressChangeReceiver, intentProgressChangeFilter);</span>


        try {
            int msg = intent.getIntExtra("MSG", 0);
            musicPath = intent.getStringExtra("url");
            SendBroadcastToActivity(intent);


            if (msg == AppConstant.PlayerMsg.PLAY_MSG) {
                myHandler.sendEmptyMessage(PlayerMsg.PLAY_MSG);
                playMusic(0);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }


    private void playMusic(int position) {
        try {
            mediaPlayer.reset();
            mediaPlayer.setDataSource(musicPath);
            mediaPlayer.prepare();
            mediaPlayer.setOnPreparedListener(new MyPreparedListener(position));
<span style="color:#ff0000;">            initMyNotification();</span>


        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    private class MyPreparedListener implements MediaPlayer.OnPreparedListener {


        private int position;


        public MyPreparedListener(int position) {
            this.position = position;
        }


        public void onPrepared(MediaPlayer mp) {
            if (position > 0)
                mediaPlayer.seekTo(position);
            mediaPlayer.start();
        }
    }


    private void stopMusic() {
        if (mediaPlayer != null) {
            mediaPlayer.pause();
        }
    }


    public void onDestory() {
        if (mediaPlayer != null) {
            mediaPlayer.stop();
            mediaPlayer.release();
        }
    }


    private void SendBroadcastToActivity(Intent intent) {                                //向activity发送广播的函数


        music_title = intent.getStringExtra("title");
        music_artist = intent.getStringExtra("artist");
<span style="color:#ff0000;">        initMyNotification();</span>
        intent_to_activity.putExtra("title", intent.getStringExtra("title"));
        intent_to_activity.putExtra("artist", intent.getStringExtra("artist"));
        intent_to_activity.putExtra("album", intent.getStringExtra("album"));
        intent_to_activity.putExtra("album_id", intent.getLongExtra("album_id", 0));
        sendBroadcast(intent_to_activity);
    }


    private class PlayReceiver extends BroadcastReceiver {                             //播放与暂停广播接收器


        public PlayReceiver() {
            super();
        }


        @Override
        public void onReceive(Context context, Intent intent) {


            isPause = intent.getBooleanExtra("isPause", true);
            isChangToNext = intent.getBooleanExtra("isChangeToNext", false);


            if (isPause) {
                myHandler.sendEmptyMessage(PlayerMsg.PAUSE);
            } else {
                current_position = intent.getIntExtra("position", 0);
                playMusic(current_position);
                myHandler.sendEmptyMessage(PlayerMsg.PLAY_MSG);
            }
        }
    }


    private class ChangeToNextReceiver extends BroadcastReceiver {                        //换歌广播接收器


        public ChangeToNextReceiver() {
            super();
        }

        @Override
        public void onReceive(Context context, Intent intent) {

            isChangToNext = intent.getBooleanExtra("isChangeToNext", false);

            if (isChangToNext) {
                musicPath = intent.getStringExtra("music_url");
                music_artist = intent.getStringExtra("music_artist");
                music_title = intent.getStringExtra("music_title");
                playMusic(0);
<span style="color:#ff0000;">                initMyNotification();</span>
            }
        }
    }


    private class ProgressChangeReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            current_position = intent.getIntExtra("current_position", 0);
            playMusic(current_position);
        }
    }


 <span style="color:#ff0000;">   private void initMyNotification() {


        /*
        第一个参数是显示在通知栏上的小图标的图片
        第二个参数是在启动notification时,在状态栏上滚动的一句话
        第三个参数是在状态栏上显示的时间
         */
        myNotification = new Notification(R.drawable.notification_artist_default_image, "小卷毛音乐", System.currentTimeMillis());


        /*
        NotificationManager用来管理notification的显示和消失等
         */
        myNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);


        /*
        对刚才创建的一个notification实例设置各种参数
        其中的一个参数是flags
        这个参数可以设置该notification是何种状态
        这里设置的是ONGOING,表示这个notification会一直呆在通知栏上面
        也可以设置滑动后就消失的样式,看个人的不同需求
         */
        myNotification.flags = Notification.FLAG_ONGOING_EVENT;


        /*
        在我们创建的notification中有一个View子类的实例
        下面创建了一个RemoteViews的实例
        并且配置好各种显示的信息后
        将该实例传给notification
        往后面看会有一句
        myNotification.contentView = contentViews;
        这个就是传递实例了


         */
        RemoteViews contentViews = new RemoteViews(getPackageName(), R.layout.notification_layout);
        contentViews.setImageViewResource
                (R.id.notification_artist_image, R.drawable.notification_artist_default_image);


        contentViews.setTextViewText(R.id.notification_music_title, music_title);
        contentViews.setTextViewText(R.id.notification_music_Artist, music_artist);


        if(mediaPlayer.isPlaying()){
            contentViews.setImageViewResource(R.id.notification_play_button,R.drawable.play_photo);
        }
        else{
            contentViews.setImageViewResource(R.id.notification_play_button,R.drawable.pause_photo);
        }




        /*
        将处理好了的一个View传给notification
        让其在通知栏上显示
         */
        myNotification.contentView = contentViews;


        Intent previousButtonIntent = new Intent(NotificationMsg.NOTIFICATION_PREVIOUS_MUSIC);
        PendingIntent pendPreviousButtonIntent = PendingIntent.getBroadcast(this, 0, previousButtonIntent, 0);
        contentViews.setOnClickPendingIntent(R.id.notification_previous_song_button, pendPreviousButtonIntent);


        Intent nextButtonIntent = new Intent(NotificationMsg.NOTIFICATION_NEXT_MUSIC);
        PendingIntent pendNextButtonIntent = PendingIntent.getBroadcast(this, 0, nextButtonIntent, 0);
        contentViews.setOnClickPendingIntent(R.id.notification_next_song_button, pendNextButtonIntent);


        Intent playButtonIntent = new Intent(NotificationMsg.NOTIFICATION_PAUSE_MUSIC);
        PendingIntent pendPlayButtonIntent = PendingIntent.getBroadcast(this, 0, playButtonIntent, 0);
        contentViews.setOnClickPendingIntent(R.id.notification_play_button, pendPlayButtonIntent);




        Intent exitButton = new Intent(NotificationMsg.NOTIFICATION_EXIT);
        PendingIntent pendingExitButtonIntent = PendingIntent.getBroadcast(this,0,exitButton,0);
        contentViews.setOnClickPendingIntent(R.id.notification_exit_button,pendingExitButtonIntent);


        /*
        在创建的notification中还有一个intent
        Intent :意图,即告诉系统我要干什么,然后系统根据这个Intent做对应的事。
        如startActivity相当于发送消息,而Intent是消息的内容。
        PendingIntent :包装Intent,Intent 是我们直接使用 startActivity , startService 或 sendBroadcast 启动某项工作的意图。
        而某些时候,我们并不能直接调用startActivity , startServide 或 sendBroadcast ,而是当程序或系统达到某一条件才发送Intent。
        如这里的Notification,当用户点击Notification之后,由系统发出一条Activity 的 Intent 。
        因此如果我们不用某种方法来告诉系统的话,系统是不知道是使用 startActivity ,startService 还是 sendBroadcast 来启动Intent 的(当然还有其他的“描述”),
        因此这里便需要PendingIntent。


        PendingIntent.getActivity的参数依次为:Context,发送者的请求码(可以填0),用于系统发送的Intent,标志位
         */
        Intent notificationIntent = new Intent(this, MainActivity.class);
        PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
        myNotification.contentIntent = contentIntent;




        /*
        用notificationManager来启动notification
        通过调用notify这个函数来启动
         */
        myNotificationManager.notify(0, myNotification);
    }</span>




    <span style="color:#ff0000;">BroadcastReceiver onClickReceiver = new BroadcastReceiver() {


        @Override
        public void onReceive(Context context, Intent intent) {


            Boolean notification_previous_music = false;
            Boolean notification_next_music = false;
            Boolean notification_pause_music = false;
            Boolean notification_exit = false;


            notification_msg = intent.getAction();


            if (notification_msg.equals(NotificationMsg.NOTIFICATION_PREVIOUS_MUSIC)) {
                notification_previous_music = true;
            }


            if(notification_msg.equals(NotificationMsg.NOTIFICATION_NEXT_MUSIC)){
                notification_next_music = true;
            }


            if(notification_msg.equals(NotificationMsg.NOTIFICATION_PAUSE_MUSIC)){
                if(mediaPlayer.isPlaying()){
                    notification_pause_music = true;
                    initMyNotification();
                    stopMusic();
                }
                else{
                    playMusic(current_position);
                    initMyNotification();
                }
            }


            if(notification_msg.equals(NotificationMsg.NOTIFICATION_EXIT)){


                notification_exit = true;
                myNotificationManager.cancelAll();
            }


            notification_to_activity.putExtra("notification_previous_music",notification_previous_music);
            notification_to_activity.putExtra("notification_next_music",notification_next_music);
            notification_to_activity.putExtra("notification_pause_music",notification_pause_music);
            notification_to_activity.putExtra("notification_exit",notification_exit);


            sendBroadcast(notification_to_activity);
        }
    };</span>
}






上面在notification的按钮点击之后,先在service里面做了处理,然后再发广播通知activity做出相应的处理.(
<span style="color:#ff0000;">sendBroadcast(notification_to_activity);</span>
)

在activity中的部分代码如下:

    private boolean notification_previous_music;                           //通知栏上一首
private boolean notification_next_music; //通知栏下一首
private boolean notification_pause_music; //通知栏停止播放
private boolean notification_exit; //通知栏退出

private NotificationReceiver notificationReceiver; //通知栏广播接收器

notificationReceiver = new NotificationReceiver();

IntentFilter intentNotificationFilter = new IntentFilter();
intentNotificationFilter.addAction("com.example.communication.NOTIFICATION_TO_ACTIVITY");
registerReceiver(notificationReceiver,intentNotificationFilter);



private class NotificationReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {

notification_previous_music = intent.getBooleanExtra("notification_previous_music",false);
notification_next_music = intent.getBooleanExtra("notification_next_music",false);
notification_pause_music = intent.getBooleanExtra("notification_pause_music",false);
notification_exit = intent.getBooleanExtra("notification_exit",false);

if(notification_previous_music){
changeMusic(play_mode,AppConstant.PlayerMsg.PREVIOUS_MUSIC,mp3Infos);
}

if(notification_next_music){
changeMusic(play_mode,AppConstant.PlayerMsg.NEXT_MUSIC,mp3Infos);
}

if(notification_pause_music){
play_button.setImageResource(R.drawable.play_photo);
}
else{
play_button.setImageResource(R.drawable.pause_photo);
}

if(notification_exit){
System.exit(0);
}
}
}

        代码很简单,读读就能懂哈,这篇给的代码有点长了,主要介绍的notification的用法,后面的一大段一大段是接着前面的项目在继续,大家可以选择性的看一看.

         

         在下一期博客中,我们将介绍android上的数据库使用,记录最近播放的音乐,也差不多快到尾声了,这个小系列从2014年写到了2015年,估计是最长时间的了,,,23333Android 音乐播放器的开发教程(十)通知栏Notification的使用 ----- 小达.今天就写到这里咯,明天见~~~~~88