【Android】23.0 手机多媒体(一)——通知(Notification)(1):状态栏显示通知

1.0 通知(Notification),这个内容网上可以找到很多介绍,但是:
  • 要么都没有更新到Android O(API 26,Android 8)系统以上.
  • 要么篇幅太短,打油诗级别的介绍
  • 要么一篇博文全部怼完,乱七八糟不说,理解起来不知道从哪捋思路。
  • 也因为Android版本更新的原因,一些方法被弃用,导致现如今网上的很多关于 通知(Notification)的代码无法顺利编译,或者用Android studio编写时,方法上已经划横线了。
  • 事实上面对国内各种深度定制的Android系统,通知(Notification)可能存在其他乱七八糟的缺陷
    备注:所以,本篇更新至今天,最新版本(2019-02-21)
2.0 本篇主要是通过一个简单的项目实现顺利地发出一条状态栏通知,会尽量在项目中精简代码,将系统性的理论知识放最后分类补充。

可参考文章:
链接:Android Notification 详解
链接:# Android 通知栏Notification的整合全面学习
链接:Android通知栏(Notification)介绍及使用

3.0 新建一个项目,Notificationtest,目录如下:
2019-02-21_165013.png

备注:为什么不把源代码上传到Gittub?因为Android编程的尿性,更新换代很快,今天能运行的代码,明天不一定能跑得起来(而且配置文件超多)。所以习惯性展示目录和代码,可以避免某些参考时可能存在的版本兼容问题。

4.0 布局文件中就一个控件:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/send_notice"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="发送通知"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.05" />

</android.support.constraint.ConstraintLayout>
5.0 划线的重点来了,需要解决新版本的兼容问题

由于升级到Android O(安卓欧,不是安卓零)版本后,一些方法被弃用,而且Android O引入了通知渠道Notification Channels),以提供统一的系统来帮助用户管理通知,如果是针对 android O 为目标平台时,必须实现一个或者多个通知渠道(就是要new NotificationChannel()),以向用户显示通知。比如聊天软件,为每个聊天组设置一个通知渠道,指定特定声音、灯光等配置。

6.0 先解决状态栏通知显示需要干什么,再解决考虑到Android O版本还需要做什么。
6.1 通知显示需要3步走
  • 1.第1步:获取状态通知栏管理:
  • 2.第2步:实例化通知栏构造器NotificationCompat.Builder
  • 3第3步:对Builder进行配置:
    (第3步和第2步之间本来还有1步的,但是不是必要,放下一章讲解——通知栏点击事件处理

6.1.1 状态栏通知的管理类 NotificationManager,负责发通知、清除通知等操作。

注意:NotificationManager是一个系统Service,
所以必须通过 getSystemService (NOTIFICATION_SERVICE)方法来获取。

6.1.2 实例化通知栏构造器通过声明Notification

一个 Notification 的必要属性有三项,如果不设置则在运行时会抛出异常:

  • 小图标,通过 setSmallIcon()方法设置
  • 标题,通过 setContentTitle()方法设置
  • 内容,通过 setContentText()方法设置

除了这3种还有:

  • setWhen() 通知产生的时间。会在通知信息里显示,通常是系统获取到的时间:setWhen( System.currentTimeMillis() )
  • setLargeIcon() 设置通知大ICON
  • setPriority 设置通知优先级
  • setOngoing(false) 设置它为一个正在进行的通知。他们通常是用来表示一个后台任务,用户积极参与(如播放音乐)或以某种方式正在等待,因此占用设备(如一个文件下载,同步操作,主动网络连接)
  • setNumber( ) 设置通知集合的数量
  • setStyle( ) 设置
  • setAutoCancel(true) 设置这个标志当用户单击面板就可以让通知将自动取消(手机QQ就是设置成false,所以你在通知栏总是取消不掉它)
  • setTicker( ) 设置通知首次出现在通知栏,带上升动画效果的
  • setContentIntent(getDefalutIntent(Notification.FLAG_AUTO_CANCEL)) 设置设置通知栏点击意图
  • setDefaults(int defualts) 为了精简学习难度,Notification 的通知效果知识点本章不写。(通过setDefaults(int defualts)方法来设置。一旦设置了Default 效果,自定义的效果就会失效。Default 效果可以相互组合)

    6.1.3 第3步,只需要调用NotificationManagernotify()方法就可以让通知显示出来。

notify()方法接收2个参数:

  • 第一个参数是id,保证每个通知的id都是不一样的。
  • 第二个参数是指Notification对象,将第二步建好的Notification对象传入即可。这样显示一个通知就可以写成:
 NotificationManager manager =
                        (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
                Notification notification = null;
...
manager.notify(1, notification);

OK,理论讲完,继续往下走

7.0 综合上面理论知识,下面MainActivity.java中的代码,看懂就没什么大问题了。
package com.example.notificationtest;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.support.v4.app.NotificationCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private String id = "channel_001";
    private String name = "name";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button sendNotice = (Button) findViewById(R.id.send_notice);
        sendNotice.setOnClickListener(this);
    }

    @RequiresApi(api =26)
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.send_notice:

                //第一步:获取状态通知栏管理:

                NotificationManager manager =
                        (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
                Notification notification = null;
                //第二步:实例化通知栏构造器NotificationCompat.Builder:
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {//判断API
                    NotificationChannel mChannel = new NotificationChannel(id, name,
                            NotificationManager.IMPORTANCE_LOW);
                    manager.createNotificationChannel(mChannel);

                    notification = new NotificationCompat.Builder(this, id)

                            .setContentTitle("这是一个内容标题")//设置通知栏标题
                            .setContentText("这是一个内容文本") //设置通知栏显示内容
                            .setWhen(System.currentTimeMillis())//通知产生的时间。
                            // 会在通知信息里显示,通常是系统获取到的时间
                            .setSmallIcon(R.mipmap.ic_launcher)//设置通知小ICON
                            .setLargeIcon(BitmapFactory.decodeResource(getResources()
                                    , R.mipmap.ic_launcher))//设置通知大ICON
                            .build();
                } else {
                    NotificationCompat.Builder notificationBuilder =
                            new NotificationCompat.Builder(this, id)
                                    .setContentTitle("这是一个内容标题")
                                    .setContentText("这是一个内容文本")
                                    .setSmallIcon(R.mipmap.ic_launcher)
                                    .setLargeIcon(BitmapFactory.decodeResource(getResources()
                                            , R.mipmap.ic_launcher));
//                                    .setOngoing(true);
                    notification = notificationBuilder.build();
                }
                //第三步:对Builder进行配置:
                manager.notify(1, notification);
                break;
            default:
                break;
        }
    }
}

需要注意的两个方面:

  • 用的实现implements关键字实现监控的接口,这是因为在经常用的内部类中,用NotificationCompat.Builder(Context context, String channelId)报错……
  • 网上代码基本都是用NotificationCompat.Builder(Context context)方法,但这个方法已经弃用,最新版本NotificationCompat.Builder(Context context, String channelId)channelId在一开始就随便申明一个就好……
  • 关于解决Android O兼容性问题,看9.0
8.0 解决Android O版本兼容性问题(好吧,本来想放在6.2的):在Android 8版本及以上按网上大部分的代码来写,是不会显示状态栏通知的。

需要用到如上代码中if语句来处理,记得声明@RequiresApi(api =26)
下面开始解释下这个逻辑,把上面MainActivity.javaif语句代码抄下来如下所示:

  //如果当前Android的版本相比Android O,一样或者版本更高,就建通知渠道(Notification Channels )
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {//判断API
                    //1.0 建渠道
                    NotificationChannel mChannel = new NotificationChannel(id, name,
                            NotificationManager.IMPORTANCE_LOW);
                    //2.0 把通知渠道通过createNotificationChannel( )方法给-
                    //      -状态栏通知的管理类 NotificationManager 
                    manager.createNotificationChannel(mChannel);
                   //3.0 Notification这时候可以正常工作了 
                    notification = new NotificationCompat.Builder(this, id)
                            .setContentTitle("这是一个内容标题")//设置通知栏标题
                            .setContentText("这是一个内容文本") //设置通知栏显示内容
                            .setWhen(System.currentTimeMillis())//通知产生的时间。
                            // 会在通知信息里显示,通常是系统获取到的时间
                            .setSmallIcon(R.mipmap.ic_launcher)//设置通知小ICON
                            .setLargeIcon(BitmapFactory.decodeResource(getResources()
                                    , R.mipmap.ic_launcher))//设置通知大ICON
                            .build();
                } else {
                    //如果当前Android的版本比Android O(API 26)版本要低
                    //直接开始上面的3.0步骤——Notification这时候就可以正常工作了 
                    NotificationCompat.Builder notificationBuilder =
                            new NotificationCompat.Builder(this, id)
                                    .setContentTitle("这是一个内容标题")
                                    .setContentText("这是一个内容文本")
                                    .setSmallIcon(R.mipmap.ic_launcher)
                                    .setLargeIcon(BitmapFactory.decodeResource(getResources()
                                            , R.mipmap.ic_launcher));
//                                    .setOngoing(true);
                    notification = notificationBuilder.build();
                     //为什么if语句里面两个3.0不一样
                     // notification =
                     //       new NotificationCompat.Builder(this, id)
                     //               .setContentTitle("这是一个内容标题")
                     //               .setContentText("这是一个内容文本")
                     //               .setSmallIcon(R.mipmap.ic_launcher)
                     //               .setLargeIcon(BitmapFactory.decodeResource(getResources()
                     //                       , R.mipmap.ic_launcher)).build();
                    //这几行代码就一样了。
                }

如上。

9.0 执行项目(如果你的手机系统版本是Android 8.0.0版本及以上,建议用真机测试,真机测试更自信):

现在Android 9.0.0(API 28)模拟器运行:

2019-02-21_195725.png

点击“发送通知”按钮,最上方标题栏出现一个小白点

2019-02-21_195731.png

下拉状态栏,查看:


2019-02-21_195737.png

接下来在Android 7.0.0(API 24)模拟器运行:

2019-02-21_195831.png

点击“发送通知”按钮,最上方标题栏出现一个小白点

2019-02-21_195837.png

下拉状态栏,查看:


2019-02-21_195844.png
10.0 如果你使用的是Android手机,此时应该会下意识地认为这条通知是可以点击的。

但你去点击的时候,你会发现没有任何效果。它是不会因为你可能是中国人就给你面子的……
可以参考我的下一篇:
链接:【Android】24.0 手机多媒体(二)——通知(Notification)(2):状态栏通知点击事件处理

END

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容