美文网首页android功能调用
31.android 通知栏详解

31.android 通知栏详解

作者: TensorFlow开发者 | 来源:发表于2018-02-05 10:19 被阅读404次

    场景

    开发过程中,经常会使用状态栏来通知用户。且不同的应用,状态栏的样式也差异万千,需要自定义。今天就总结一下安卓中的通知栏(Notification)知识。

    本文结构主要分为:

    • Notification 通知的作用
    • 通知栏常见类型
    • Notification的基本用法
    • 自定义通知栏

    1. Notification 通知的作用

    从JellyBean 以来,通知系统做了一次被引入Android 以来最重大的结构性和功能性的变动。

    通知可以包含操作,用户可以在通知抽屉中直接做出回应
    通知在大小和布局方面更加灵活,可以展开显示更多的信息
    通知有了优先级高低的排列方式,而不仅仅是时间的排列

    通知状态栏的作用

    1.显示接收短消息以及即时信息等(短信 ,QQ,微信等)
    2.显示客户端的推送消息 (广告,推荐消息等)
    3.显示正在进行的事务 (播放器的显示,版本更新等)

    2. Notification的基本用法

    通知的基本用法还是很灵活的,可以在活动中创建,也可以在广播接收器中创建,还可以在服务中创建。一般在广播和服务中用的比较多,因为只有在程序进入后台的时候,我们才需要使用通知,活动中使用的比较少。

    Notification视觉风格

    Notification有两种视觉风格,一种是标准视图(Normal view)、一种是大视图(Big view)。标准视图在Android中各版本是通用的,但是对于大视图而言,仅支持Android4.1+的版本。

    从官方文档了解到,一个标准视图显示的大小要保持在64dp高,宽度为屏幕标准。
    标准视图的通知主体内容有一下几个:
    1.通知标题。
    2.大图标。
    3.通知内容。
    4.通知消息。
    5.小图标。
    6.通知的时间,一般为系统时间,也可以使用setWhen()设置。

    而对于大视图(Big View)而言,它的细节区域只能显示256dp高度的内容,并且只对Android4.1+之后的设备才支持,它比标准视图不一样的地方,均需要使用setStyle()方法设定

    • setStyle()传递一个NotificationCompat.Style对象,它是一个抽象类,Android为我们提供了三个实现类,用于显示不同的场景。分别是:
    NotificationCompat.BigPictureStyle, 在细节部分显示一个256dp高度的位图。
    NotificationCompat.BigTextStyle,在细节部分显示一个大的文本块。
    NotificationCompat.InboxStyle,在细节部分显示一段行文本。
    

    2.1 通知的基本布局

    通知的基本布局包括:

    • 发送通知的应用图标或者发送人的头像
    • 通知标题和消息
    • 时间戳
    • 当主图标显示发送人头像时,在副图标位置显示应用图标
    通知的基本布局示意图

    2.2 通知的扩展布局

    通知的扩展布局显示消息的前面几行或者图片的预览,后面的信息折叠起来,这样用户就可以看到更多的信息。用户可以通过 pinch-zoom 或者双手指滑动来打开扩展布局。Android 为单条消息提供了两种扩展布局 (文字和图像) 供你开发应用时使用。


    通知的扩展布局示意图

    从 Jelly Bean 开始,Android 支持在通知底部显示附加操作。通过这些操作,用户可以对通知直接执行常见的任务,而不用打开应用。这样可以加快操作,配合上滑出消失操作,使用户的通知抽屉体验更加顺滑。
    可以放入通知中的操作有以下特点:

    • 对于该通知重要、常用和典型的操作
    • 时间紧迫的
    • 不会与相邻的操作重复的

    不要放置:

    • 模糊的
    • 和点击通知得到的效果一样的操作,例如阅读或者打开

    2.3 通知的优先级

    从 Jelly Bean 开始,Android 为通知增加了优先级标志。这样你可以使重要的通知相对于其他通知,总是显示在第一个。请通过以下的表格仔细选择通知的优先级


    通知的优先级I 通知的优先级II

    2.4 创建通知的步骤

    1.创建一个通知管理类NotificationManager,通过调用 getSystemService()的方法获得。getSystemService方法接收一个字符串参数用于确定获取系统的哪个服务,传入Context.NOTIFICATION_SERVICE

    NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);  
    
    1. 使用Builder构造器创建Notification对象。这里使用 support-v4库中提供的NotificationCompat
    NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context);  
    或者这样写:
    Notification notification = NotificationCompat.Builder(context).builder();
    

    3.对Builder进行配置(写法和dialog差不多)

        mBuilder.setContentTitle("通知栏标题")        // 设置通知栏标题  
        .setContentText("通知栏显示内容")              // 设置通知栏显示内容
        .setContentIntent(getDefalutIntent(Notification.FLAG_AUTO_CANCEL)) //设置通知栏点击意图  
        .setNumber(number)                           // 设置通知集合的数量  
        .setTicker("测试通知来啦")                    // 通知首次出现在通知栏,带上升动画效果的  
        .setWhen(System.currentTimeMillis())        // 通知产生的时间,会在通知信息里显示,一般是系统获取到的时间  
        .setPriority(Notification.PRIORITY_DEFAULT) // 设置该通知优先级  
        .setAutoCancel(true)                        // 设置这个标志当用户单击面板就可以让通知将自动取消    
        .setOngoing(false)                          // ture,设置他为一个正在进行的通知。他们通常是用来表示一个后台任务,用户积极参与(如播放音乐)或以某种方式正在等待,因此占用设备(如一个文件下载,同步操作,主动网络连接)  
        .setDefaults(Notification.DEFAULT_VIBRATE)  // 向通知添加声音、闪灯和振动效果的最简单、最一致的方式是使用当前的用户默认设置,使用defaults属性,可以组合  
        //Notification.DEFAULT_ALL  Notification.DEFAULT_SOUND 添加声音 // requires VIBRATE permission  
        .setSmallIcon(R.drawable.ic_launcher);      // 设置通知小ICON  
    

    4.设置通知栏PendingIntent(点击动作事件等都包含在这里)。PendingIntent 从名字上看和Intent 很像,它们都指明一个意图,都可以开启活动,开启服务和发送广播。但是Intent 倾向于立即执行某个动作,而PendingIntent 倾向于某个时机执行动作。

    5.最后一步,发送通知请求

    mNotificationManager.notify(notifyId, mBuilder.build());  
    

    notify()方法有两个参数,一个参数是id,要保证每个通知所指定的id都是不同的,第二个参数则是Notification对象。
    显示一个通知:

    mNotificationManager.notify(1, mBuilder.build());
    

    2.5 通知的方法

    1. 设置提醒的标志符号flags,添加声音,设置闪灯,震动等效果。

    两种设置方法:
    1). 实例化之后,在设置flags

    Notification notification = mBuilder.build();  
    notification.flags = Notification.FLAG_AUTO_CANCEL;
    

    2). 通过setContentIntent(PendingIntent intent)方法中的意图设置对应的flags

    public PendingIntent getDefalutIntent(int flags){  
        PendingIntent pendingIntent= PendingIntent.getActivity(this, 1, new Intent(), flags);  
        return pendingIntent;  
    } 
    

    提醒标志符成员:

    Notification.FLAG_SHOW_LIGHTS //三色灯提醒,在使用三色灯提醒时候必须加该标志符
    Notification.FLAG_ONGOING_EVENT //发起正在运行事件(活动中)
    Notification.FLAG_INSISTENT //让声音、振动无限循环,直到用户响应 (取消或者打开)
    Notification.FLAG_ONLY_ALERT_ONCE //发起Notification后,铃声和震动均只执行一次
    Notification.FLAG_AUTO_CANCEL //用户单击通知后自动消失
    Notification.FLAG_NO_CLEAR //只有全部清除时,Notification才会清除 ,不清楚该通知(QQ的通知无法清除,就是用的这个)
    Notification.FLAG_FOREGROUND_SERVICE //表示正在运行的服务
    
    1. setDefaults(int defaults) (NotificationCompat.Builder中的方法,用于提示)
      功能:向通知添加声音、闪灯和振动效果的最简单、使用默认(defaults)属性,可以组合多个属性(和方法1中提示效果一样的)
      对应属性:
    Notification.DEFAULT_VIBRATE //添加默认震动提醒 需要 VIBRATE permission
    Notification.DEFAULT_SOUND // 添加默认声音提醒
    Notification.DEFAULT_LIGHTS// 添加默认三色灯提醒
    Notification.DEFAULT_ALL// 添加默认以上3种全部提醒
    
    1. setVibrate(long[] pattern)
      功能:设置震动方式
    .setVibrate(new long[] {0,300,500,700});  // 实现效果:延迟0ms,然后振动300ms,在延迟500ms,接着在振动700ms。
    

    写法二:

    mBuilder.build().vibrate = new long[] {0,300,500,700};  
    

    小提示:

    如果没有震动效果,检查是否添加了震动权限:

        <!-- 振动器权限 -->
        <uses-permission android:name="android.permission.VIBRATE" />
    
    1. setLights(intledARGB ,intledOnMS ,intledOffMS )
      功能:android支持三色灯提醒,这个方法就是设置不同场景下的不同颜色的灯。
      描述:其中ledARGB 表示灯光颜色、 ledOnMS 亮持续时间、ledOffMS 暗的时间。
      注意:
      1)只有在设置了标志符Flags为Notification.FLAG_SHOW_LIGHTS的时候,才支持三色灯提醒。
      2)这边的颜色跟设备有关,不是所有的颜色都可以,要看具体设备。
    .setLights(0xff0000ff, 300, 0) 
    

    同理,实现同样的效果:

    Notification notify = mBuilder.build();  
    notify.flags = Notification.FLAG_SHOW_LIGHTS;  
    notify.ledARGB = 0xff0000ff;  
    notify.ledOnMS = 300;  
    notify.ledOffMS = 300;  
    

    如果希望使用默认的三色灯提醒,设置了方法(2)中默认为DEFAULT_LIGHTS即可。

    1. setSound(Uri sound)
      功能:设置默认或则自定义的铃声,来提醒。
    //获取默认铃声  
    .setDefaults(Notification.DEFAULT_SOUND)  
    //获取自定义铃声  
    .setSound(Uri.fromFile(new File("file:///sdcard/xx/xx.mp3")))  
    //获取Android多媒体库内的铃声  
    .setSound(Uri.withAppendedPath(Audio.Media.INTERNAL_CONTENT_URI, "5"))  
    

    小提示:

    如果没有闪光灯、震动效果,检查是否添加了相应权限:

       <!-- 闪光灯权限 -->
        <uses-permission android:name="android.permission.FLASHLIGHT" />
        <!-- 振动器权限 -->
        <uses-permission android:name="android.permission.VIBRATE" />
    
    1. setPriority(int pri)
      对应属性(作用看上图就可知道):
    Notification.PRIORITY_DEFAULT
    Notification.PRIORITY_HIGH
    Notification.PRIORITY_LOW
    Notification.PRIORITY_MAX
    Notification.PRIORITY_MIN
    
    通知的优先级I
    1. setOngoing(boolean ongoing)
      功能:设置为ture,表示它为一个正在进行的通知。他们通常是用来表示一个后台任务,用户积极参与(如播放音乐)或以某种方式正在等待,因此占用设备(如一个文件下载,同步操作,主动网络连接)
    2. setProgress(int max, int progress,boolean indeterminate)
      属性:max:进度条最大数值 、progress:当前进度、indeterminate:表示进度是否不确定,true为不确定,如下第3幅图所示 ,false为确定下第1幅图所示
      功能:设置带进度条的通知,可以在下载中使用
    带进度条的通知
    1. 设置点击取消
      点击通知消息之后,上面的图标还是没有消掉。
      比发送最简单的通知,发送具有 Action 的通知多了创建 Intent 、 PendingIntent 和 setContentIntent() 这几步。
      1)在buider配置的方法中添加
    .setAutoCancel(true)
    

    2 ) 在创建管理通知类NotificationManager的时候,调用cancel()方法

    NotificationManager manager= (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);  
    manager.cancel(1);// 这里的这个1 ,是在创建通知的时候给每条通知指定的notifyId 。因此如果你想取消哪条id就传哪个值。
    

    2.6 PendingIntent 的用法

    PendingIntent的用法很简单。它主要提供了几个静态方法用于获取PendingIntent的实现,可以根据需求使用getActivity()方法,getBroadcast()方法,getService()方法,这几个方法里面的参数都是一样的。第一个参数是Context ,第二个参数一般用不到传个0就好,第三个参数是一个Intent的对象,通过它来构建PendingIntent的“意图”,第四个用于确定PendingIntent的行为.
    2.6.1 PendingIntent的位标识符:
    FLAG_ONE_SHOT 表示返回的PendingIntent仅能执行一次,执行完后自动取消
    FLAG_NO_CREATE 表示如果描述的PendingIntent不存在,并不创建相应的PendingIntent,而是返回NULL
    FLAG_CANCEL_CURRENT 表示相应的PendingIntent已经存在,则取消前者,然后创建新的PendingIntent,这个有利于数据保持为最新的,可以用于即时通信的通信场景
    FLAG_UPDATE_CURRENT 表示更新的PendingIntent

    2.6.2 在各种情况下情况下它还会根据各种情况触发效果:
    contentIntent:在通知窗口区域,Notification被单击时的响应事件由该intent触发;
    deleteIntent:当用户点击全部清除按钮时,响应该清除事件的Intent;
    fullScreenIntent:响应紧急状态的全屏事件(例如来电事件),也就是说通知来的时候,跳过在通知区域点击通知这一步,直接执行fullScreenIntent代表的事件。
    1). 点击通知栏跳转到指定的XXActivity中

    Intent intent = new Intent(context,XXX.class);  
    PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);  
    mBuilder.setContentIntent(pendingIntent)
    

    小提示

    Android通知栏点击无法启动Activity时,请检查该Activity是否添加了该属性: android:exported="true"。例如:

    <activity android:name=".BootActivity"
                android:exported="true"/>
    

    2). 在执行了清空全部的通知操作时候,可以设置以下方法来相应这个事件

    Intent deleteIntent = new Intent();  
    deleteIntent.setClass(context, XXXReceiver.class);  
    deleteIntent.setAction(DELETE_ACTION);  
    notification.deleteIntent = PendingIntent.getBroadcast(context, 0, deleteIntent, 0);  
    

    3). 在响应紧急事件(如来电)时候,可以设置以下方法来相应这个事件

    setFullScreenIntent(PendingIntent intent, boolean highPriority)
    

    小提示

    关于 setSmallIcon() 与 setLargeIcon()。
    在 NotificationCompat.Builder 中有设置通知的大小图标的两个方法。这两个方法有什么区别呢?当 setSmallIcon() 与 setLargeIcon() 同时存在时, smallIcon 显示在通知的右下角, largeIcon 显示在左侧;当只设置 setSmallIcon() 时, smallIcon 显示在左侧。

    setSmallIcon() 与 setLargeIcon()

    2.7 更新 Notification

    更新通知很简单,只需要再次发送相同 ID 的通知即可,如果之前的通知还未被取消,则会直接更新该通知相关的属性;如果之前的通知已经被取消,则会重新创建一个新通知。

    更新通知跟发送通知使用相同的方式。详见上节:创建 Notification

    2.8 取消 Notification

    取消通知有如下 5 种方式:

    点击通知栏的清除按钮,会清除所有可清除的通知

    设置了 setAutoCancel() 或 FLAG_AUTO_CANCEL 的通知,点击该通知时会清除它
    通过 NotificationManager 调用 cancel(int id) 方法清除指定 ID 的通知
    通过 NotificationManager 调用 cancel(String tag, int id) 方法清除指定 TAG 和 ID 的通知
    通过 NotificationManager 调用 cancelAll() 方法清除所有该应用之前发送的通知
    

    注意:如果你是通过 NotificationManager.notify(String tag, int id, Notification notify) 方法创建的通知,那么只能通过 NotificationManager.cancel(String tag, int id) 方法才能清除对应的通知,调用NotificationManager.cancel(int id) 无效。

    3. 创建自定义的通知栏

    Notification的自定义布局是RemoteViews,和其他RemoteViews一样,在自定义视图布局文件中,仅支持FrameLayout、LinearLayout、RelativeLayout三种布局控件和AnalogClock、Chronometer、Button、ImageButton、ImageView、ProgressBar、TextView、ViewFlipper、ListView、GridView、StackView和AdapterViewFlipper这些显示控件,不支持这些类的子类或Android提供的其他控件。否则会引起ClassNotFoundException异常

    效果图
    自定义的通知栏效果图

    3.1 创建自定义的步骤

    1). 创建自定义的视图
    2). 获取远程视图对象
    3). 设置PendingIntent(来响应各种事件)
    4). 发起Notification

    1.创建自定义的视图

    <?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="64dp"
        android:orientation="horizontal"
        android:background="#789"
        android:id="@+id/containor">
    
        <ImageView
            android:id="@+id/iv_not_head_image"
            android:layout_height="80dp"
            android:layout_width="80dp"
            android:layout_gravity="center_vertical"
    
            android:background="#789"
            android:padding="10dp"
            android:src="@drawable/ic_xingming"
            android:scaleType="fitCenter"
            />
        <LinearLayout
            android:layout_width="0dp"
            android:layout_weight="2.5"
            android:layout_height="match_parent"
            android:orientation="vertical"
            android:background="#0093fe">
            <TextView
                android:id="@+id/tv_top_title"
                android:layout_width="match_parent"
                android:layout_height="0dp"
                android:layout_weight="1"
                android:text="top"
                android:gravity="center"
                android:textColor="#fff"
                android:textSize="18sp"/>
            <TextView
                android:id="@+id/tv_middle_title"
                android:layout_width="match_parent"
                android:layout_height="0dp"
                android:layout_weight="1"
                android:background="#0a0"
                android:text="middle"
                android:gravity="center"
                android:textColor="#fff"
                android:textSize="15sp"/>
            <TextView
                android:id="@+id/tv_bottom_title"
                android:layout_width="match_parent"
                android:layout_height="0dp"
                android:layout_weight="1"
                android:background="#050"
                android:text="bottom"
                android:gravity="center"
                android:textColor="#fff"
                android:textSize="15sp"/>
    
        </LinearLayout>
        <LinearLayout
            android:id="@+id/ll_custom_button"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:orientation="horizontal"
            android:layout_weight="2"
            android:background="#334455">
            <ImageView
                android:id="@+id/iv_not_up"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_height="match_parent"
                android:src="@drawable/icon_left"
                android:scaleType="centerInside"
                android:background="#123"
                />
            <ImageView
                android:id="@+id/iv_camera"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_height="match_parent"
                android:src="@drawable/icon_camera"
                android:scaleType="centerInside"
                />
            <ImageView
                android:id="@+id/iv_not_next"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_height="match_parent"
                android:src="@drawable/icon_right"
                android:scaleType="centerInside"
                android:background="#567"/>
    
        </LinearLayout>
    </LinearLayout>
    

    步骤2、3、4

    2). 获取远程视图对象
    3). 设置PendingIntent(来响应各种事件)

        /**
         *  自定义通知栏View
         */
        private void showNotificationRemoteView() {
    
            RemoteViews mRemoteViews= new RemoteViews(getPackageName(),R.layout.view_notification);
            mRemoteViews.setImageViewResource(R.id.iv_not_head_image, R.drawable.ic_xingming);
            mRemoteViews.setViewPadding(R.id.containor, 0, 0, 0, 0);
            mRemoteViews.setTextViewText(R.id.tv_top_title,"top");
            mRemoteViews.setTextViewText(R.id.tv_middle_title,"middle");
            mRemoteViews.setTextViewText(R.id.tv_bottom_title,"bottom");
    
            if( Build.VERSION.SDK_INT <= 9){
                mRemoteViews.setViewVisibility(R.id.ll_custom_button, View.GONE);
            }else{
                mRemoteViews.setViewVisibility(R.id.ll_custom_button, View.VISIBLE);
    
            }
    
            //点击事件处理
            Intent buttonIntent=new Intent(DataLibraryConstant.DATA_LIBRARY_CONSTANT_STATUS_KEY);
            // 头像点击
            buttonIntent.putExtra(DataLibraryConstant.DATA_LIBRARY_CONSTANT_STATUS_KEY, R.id.iv_not_head_image);
            //这里加了广播,所以INTENT的必须用getBroadcast方法
            PendingIntent intent_head_image = PendingIntent.getBroadcast(this, 1, buttonIntent, PendingIntent.FLAG_UPDATE_CURRENT);
            mRemoteViews.setOnClickPendingIntent(R.id.iv_not_head_image, intent_head_image);
            // top
            buttonIntent.putExtra(DataLibraryConstant.DATA_LIBRARY_CONSTANT_STATUS_KEY, R.id.tv_top_title);
            PendingIntent intent_title = PendingIntent.getBroadcast(this, 2, buttonIntent, PendingIntent.FLAG_UPDATE_CURRENT);
            mRemoteViews.setOnClickPendingIntent(R.id.tv_top_title, intent_title);
            // middle
            buttonIntent.putExtra(DataLibraryConstant.DATA_LIBRARY_CONSTANT_STATUS_KEY, R.id.tv_middle_title);
            PendingIntent intent_content = PendingIntent.getBroadcast(this, 3, buttonIntent, PendingIntent.FLAG_UPDATE_CURRENT);
            mRemoteViews.setOnClickPendingIntent(R.id.tv_middle_title, intent_content);
    
            // bottom
            buttonIntent.putExtra(DataLibraryConstant.DATA_LIBRARY_CONSTANT_STATUS_KEY, R.id.tv_bottom_title);
            PendingIntent intent_left = PendingIntent.getBroadcast(this, 4, buttonIntent, PendingIntent.FLAG_UPDATE_CURRENT);
            mRemoteViews.setOnClickPendingIntent(R.id.tv_bottom_title, intent_left);
            // left
            buttonIntent.putExtra(DataLibraryConstant.DATA_LIBRARY_CONSTANT_STATUS_KEY, R.id.iv_not_up);
            PendingIntent intent_play= PendingIntent.getBroadcast(this,5,buttonIntent,PendingIntent.FLAG_UPDATE_CURRENT);
            mRemoteViews.setOnClickPendingIntent(R.id.iv_not_up, intent_play);
    
            // camera
            buttonIntent.putExtra(DataLibraryConstant.DATA_LIBRARY_CONSTANT_STATUS_KEY, R.id.iv_camera);
            PendingIntent intent_camera= PendingIntent.getBroadcast(this,7,buttonIntent,PendingIntent.FLAG_UPDATE_CURRENT);
            mRemoteViews.setOnClickPendingIntent(R.id.iv_camera, intent_camera);
    
            // right
            buttonIntent.putExtra(DataLibraryConstant.DATA_LIBRARY_CONSTANT_STATUS_KEY,R.id.iv_not_next);
            PendingIntent intent_right= PendingIntent.getBroadcast(this,6,buttonIntent,PendingIntent.FLAG_UPDATE_CURRENT);
            mRemoteViews.setOnClickPendingIntent(R.id.iv_not_next, intent_right);
    
    
    
            NotificationManager manager= (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
            NotificationCompat.Builder  builder= new NotificationCompat.Builder(this);
            builder.setContent(mRemoteViews);
            builder.setWhen(System.currentTimeMillis());
            builder.setPriority(NotificationCompat.PRIORITY_MAX);
            builder.setOngoing(true);
            builder.setSmallIcon(R.drawable.ic_icon_time);
            builder.setAutoCancel(true);
            manager.notify(2, builder.build());
    
    
        }
    

    更多了解,可关注公众号:人人懂编程


    微信公众号:人人懂编程

    相关文章

      网友评论

        本文标题:31.android 通知栏详解

        本文链接:https://www.haomeiwen.com/subject/tlhbzxtx.html