Notification通知欄

目錄介紹

  • 1.Notification簡單概述
  • 2.Notification通知用途
  • 3.Notification的基本操作
  • 3.1 Notification創建必要的屬性
  • 3.2 Notification簡單創建步驟
  • 3.3 關於setSmallIcon()與setLargeIcon()區別
  • 3.4 Notification的Action屬性【交互作用】
  • 3.5 更新Notification
  • 3.6 取消Notification
  • 3.7 設置flag屬性
  • 3.8 設置Notification的通知效果
  • 3.9 設置自定義Notification通知欄佈局
  • 4.Notification相關屬性說明
  • 4.1 PendingIntent說明
  • 4.2 創建返回棧PendingIntent
  • 4.3 注意要點
  • 5.部分源碼分析思考
  • 5.1 RemoteView是什麼?
  • 5.2 查看源碼,瞭解Notification如何創建佈局
  • 6.關於Android8.0通知欄適配
    • 6.1 Android O(8.0)通知的改變
    • 6.2 報錯內容和解決方案
    • 6.3 最終解決方案
  • 7.關於其他

好消息

  • 已經解決了8.0以上通知欄不能顯示問題。封裝成了lib庫,歡迎大家下載。已經放到正式項目運行多時!
  • 項目地址鏈接:https://github.com/yangchong211/YCNotification
  • 本篇文章已授權微信公衆號 guolin_blog (郭霖)獨家發佈
  • 項目截圖說明
    • image

1.Notification簡單概述

  • Notification,是一種具有全局效果的通知,可以在系統的通知欄中顯示。當 APP 向系統發出通知時,它將先以圖標的形式顯示在通知欄中。用戶可以下拉通知欄查看通知的詳細信息。通知欄和抽屜式通知欄均是由系統控制,用戶可以隨時查看。

2.Notification通知用途

  • 常見的用途
  • 顯示接收到短消息、及時消息等信息(如QQ、微信、新浪、短信)
  • 顯示客戶端的推送消息,如廣告、優惠、版本更新、推薦新聞等,常用的第三方 SDK 有: JPush 、 個推 、 信鴿 、 網易雲信(偏重 IM ) 、 阿里雲推送
  • 顯示正在進行的事物,例如:後臺運行的程序,如音樂播放進度、下載進度等
  • 前兩點可以歸結爲與用戶交互,第三點是實時的任務提醒,但不可否認的是,第三點也會與用戶交互。

3.Notification的基本操作

  • 3.1 Notification創建必要的屬性,必須設置
  • 3.1.1 必須添加的屬性
  • 小圖標,通過 setSmallIcon() 方法設置
  • 標題,通過 setContentTitle() 方法設置
  • 內容,通過 setContentText() 方法設置

  • 3.2 Notification創建步驟
  • 3.2.1 Notification 的創建主要涉及到 Notification.Builder 、 Notification 、 NotificationManager
    Notification.Builer : 使用建造者模式構建 Notification 對象。由於 Notification.Builder 僅支持 Android 4.1及之後的版本,爲了解決兼容性問題, Google 在 Android Support v4 中加入了 - NotificationCompat.Builder 類。對於某些在 Android 4.1 之後才特性,即使 NotificationCompat.Builder 支持該方法,在之前的版本中也不能運行。
  • Notification : 通知對應類,保存通知相關的數據。- NotificationManager 向系統發送通知時會用到。
  • NotificationManager : NotificationManager 是通知管理類,它是一個系統服務。調用 NotificationManager 的 notify() 方法可以向系統發送通知。

  • 3.2.2 Notification創建步驟與代碼

    // 創建一個NotificationManager的引用
    NotificationManager mNotificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
    // 定義Notification的各種屬性
    Notification.Builder mBuilder = new Notification.Builder(this.getApplicationContext())
            .setSound(android.provider.Settings.System.DEFAULT_NOTIFICATION_URI)        //
            .setSmallIcon(R.mipmap.ic_launcher)                                         //設置通知的圖標
            .setTicker("有新消息呢")                                                     //設置狀態欄的標題
            .setContentTitle("這個是標題")                                               //設置標題
            .setContentText("這個是內容")                                                //消息內容
            .setDefaults(Notification.DEFAULT_ALL)                                      //設置默認的提示音
            .setPriority(Notification.PRIORITY_DEFAULT)                                 //設置該通知的優先級
            .setOngoing(false)                                                          //讓通知左右滑的時候不能取消通知
            .setPriority(Notification.PRIORITY_DEFAULT)                                 //設置該通知的優先級
            .setWhen(System.currentTimeMillis())                                        //設置通知時間,默認爲系統發出通知的時間,通常不用設置
            .setAutoCancel(true);                                                       //打開程序後圖標消失
    //處理點擊Notification的邏輯
    Intent resultIntent = new Intent(this, TestActivity.class);
    resultIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);           //添加爲棧頂Activity
    resultIntent.putExtra("what",5);
    PendingIntent resultPendingIntent = PendingIntent.getActivity(this,5,resultIntent,PendingIntent.FLAG_UPDATE_CURRENT);
    mBuilder.setContentIntent(resultPendingIntent);
    //發送
    mNotificationManager.notify(1, mBuilder.build());
    //結束廣播
    //mNotificationManager.cancel(1);
  • 3.3 關於setSmallIcon()與setLargeIcon()區別
  • 在 NotificationCompat.Builder 中有設置通知的大小圖標的兩個方法。這兩個方法有什麼區別呢?
  • 當 setSmallIcon() 與 setLargeIcon() 同時存在時, smallIcon 顯示在通知的右下角, largeIcon 顯示在左側
  • 當只設置 setSmallIcon() 時, smallIcon 顯示在左側。看下圖你就明白了。
  • 對於部分 ROM ,可能修改過源碼,如 MIUI 上通知的大圖標和小圖標是沒有區別的。
  • 效果如圖所示:

    • image
  • 3.4 Notification的Action屬性
  • 設置一個 Action ,這樣就可以直接跳轉到 App 的某個 Activity 、啓動一個 Service 或者發送一個 Broadcast。否則,Notification 僅僅只能起到通知的效果,而不能與用戶交互。
  • 具體代碼如下所示:

    //創建intent
    Intent resultIntent = new Intent(this, TestActivity.class);
    resultIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);           //添加爲棧頂Activity
    resultIntent.putExtra("what",5);
    PendingIntent resultPendingIntent = PendingIntent.getActivity(this,5,resultIntent,PendingIntent.FLAG_UPDATE_CURRENT);
    //發送pendingIntent
    mBuilder.setContentIntent(resultPendingIntent);
  • 3.5 更新Notification
  • 更新通知很簡單,只需要再次發送相同 ID 的通知即可,如果之前的通知還未被取消,則會直接更新該通知相關的屬性;如果之前的通知已經被取消,則會重新創建一個新通知。更新通知跟發送通知使用相同的方式。

  • 3.6 取消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.7 設置flag屬性
  • 設置FLAG_NO_CLEAR表示
  • 設置通知不能被狀態欄的清除按鈕給清除掉,也不能被手動清除,但能通過 cancel() 方法清除
  • 代碼:

    private void sendNotification9() {
        Notification.Builder mBuilder = new Notification.Builder(this.getApplicationContext())
                .setSound(android.provider.Settings.System.DEFAULT_NOTIFICATION_URI)
                .setSmallIcon(R.mipmap.ic_launcher)                                        //設置通知的圖標
                .setTicker("有新消息呢9")                                                    //設置狀態欄的標題
                .setContentTitle("這個是標題9")                                              //設置標題
                .setContentText("這個是內容9")                                                //消息內容
                .setDefaults(Notification.DEFAULT_ALL)                                      //設置默認的提示音
                .setOngoing(false)                                                          //讓通知左右滑的時候不能取消通知
                .setAutoCancel(true);                                                        //打開程序後圖標消失
        Notification notification = mBuilder.build();
        //設置 Notification 的 flags = FLAG_NO_CLEAR
        //FLAG_NO_CLEAR 表示該通知不能被狀態欄的清除按鈕給清除掉,也不能被手動清除,但能通過 cancel() 方法清除
        //flags 可以通過 |= 運算疊加效果
        notification.flags |= Notification.FLAG_NO_CLEAR;
    
        //獲取NotificationManager 對象
        mNotificationManager.notify(9, notification);
    }
    //取消通知:
    if(mNotificationManager!=null){
        mNotificationManager.cancelAll();
    }
  • 3.8 設置Notification的通知效果
  • Notification 有震動、響鈴、呼吸燈三種響鈴效果,可以通過 setDefaults(int defualts) 方法來設置。 Default 屬性有以下四種,一旦設置了 Default 效果,自定義的效果就會失效。樓主在這裏踩了坑,愣是調了半天沒找到爲什麼自定義效果會消失,忘大家慎之。
    //設置系統默認提醒效果,一旦設置默認提醒效果,則自定義的提醒效果會全部失效。具體可看源碼//添加默認震動效果,需要申請震動權限//<uses-permission android:name="android.permission.VIBRATE" />
    Notification.DEFAULT_VIBRATE
    //添加系統默認聲音效果,設置此值後,調用setSound()設置自定義聲音無效
    Notification.DEFAULT_SOUND
    //添加默認呼吸燈效果,使用時須與 Notification.FLAG_SHOW_LIGHTS 結合使用,否則無效
    Notification.DEFAULT_LIGHTS
    //添加上述三種默認提醒效果
    Notification.DEFAULT_ALL
  • 除了以上幾種設置 Notification 默認通知效果,還可以通過以下幾種 FLAG 設置通知效果。
    //提醒效果常用 Flag//三色燈提醒,在使用三色燈提醒時候必須加該標誌符
    Notification.FLAG_SHOW_LIGHTS
    //發起正在運行事件(活動中)
    Notification.FLAG_ONGOING_EVENT
    //讓聲音、振動無限循環,直到用戶響應 (取消或者打開)
    Notification.FLAG_INSISTENT
    //發起Notification後,鈴聲和震動均只執行一次
    Notification.FLAG_ONLY_ALERT_ONCE
    //用戶單擊通知後自動消失
    Notification.FLAG_AUTO_CANCEL
    //只有調用NotificationManager.cancel()時纔會清除
    Notification.FLAG_NO_CLEAR
    //表示正在運行的服務
    Notification.FLAG_FOREGROUND_SERVICE
  • 設置默認提醒
    // 添加默認聲音提醒
    builder.setDefaults(Notification.DEFAULT_SOUND);
    // 添加默認呼吸燈提醒,自動添加FLAG_SHOW_LIGHTS
    builder.setDefaults(Notification.DEFAULT_LIGHTS);
  • 設置鈴聲屬性,用的很少
    private void sendNotification11() {
        Notification.Builder builder = new Notification.Builder(this)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentTitle("我是伴有鈴聲效果的通知11")
                .setContentText("美妙麼?安靜聽~11")
                //調用系統默認響鈴,設置此屬性後setSound()會無效
                //.setDefaults(Notification.DEFAULT_SOUND)
                //調用系統多媒體褲內的鈴聲
                //.setSound(Uri.withAppendedPath(MediaStore.Audio.Media.INTERNAL_CONTENT_URI,"2"));
                //調用自己提供的鈴聲,位於 /res/values/raw 目錄下
                .setSound(Uri.parse("android.resource://com.yc.cn.ycnotification/" + R.raw.hah));
        //另一種設置鈴聲的方法
        //Notification notify = builder.build();
        //調用系統默認鈴聲
        //notify.defaults = Notification.DEFAULT_SOUND;
        //調用自己提供的鈴聲
        //notify.sound = Uri.parse("android.resource://com.yc.cn.ycnotification/"+R.raw.sound);
        //調用系統自帶的鈴聲
        //notify.sound = Uri.withAppendedPath(MediaStore.Audio.Media.INTERNAL_CONTENT_URI,"2");
        //mManager.notify(11,notify);
        mNotificationManager.notify(11, builder.build());
    }
  • 設置震動屬性

    private void sendNotification12() {
        //震動也有兩種設置方法,與設置鈴聲一樣,在此不再贅述
        long[] vibrate = new long[]{0, 500, 1000, 1500};
        Notification.Builder builder = new Notification.Builder(this)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentTitle("我是伴有震動效果的通知")
                .setContentText("顫抖吧,逗比哈哈哈哈哈~")
                //使用系統默認的震動參數,會與自定義的衝突
                //.setDefaults(Notification.DEFAULT_VIBRATE)
                //自定義震動效果
                .setVibrate(vibrate);
        //另一種設置震動的方法
        //Notification notify = builder.build();
        //調用系統默認震動
        //notify.defaults = Notification.DEFAULT_VIBRATE;
        //調用自己設置的震動
        //notify.vibrate = vibrate;
        //mManager.notify(3,notify);
        mNotificationManager.notify(12, builder.build());
    }
  • 3.9 設置自定義Notification通知欄佈局
  • 代碼如下,注意,這裏只取部分代碼,完整代碼可以下載github的完整項目:https://github.com/yangchong211/YCNotification
    .setContent(getRemoteViews())                                              // 設置通知欄的佈局
    //創建自定義佈局
    private RemoteViews getRemoteViews() {
        RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.notification_mobile_play);
        // 設置 點擊通知欄的上一首按鈕時要執行的意圖
        remoteViews.setOnClickPendingIntent(R.id.btn_pre, getActivityPendingIntent(11));
        // 設置 點擊通知欄的下一首按鈕時要執行的意圖
        remoteViews.setOnClickPendingIntent(R.id.btn_next, getActivityPendingIntent(12));
        // 設置 點擊通知欄的播放暫停按鈕時要執行的意圖
        remoteViews.setOnClickPendingIntent(R.id.btn_start, getActivityPendingIntent(13));
        // 設置 點擊通知欄的根容器時要執行的意圖
        remoteViews.setOnClickPendingIntent(R.id.ll_root, getActivityPendingIntent(14));
        remoteViews.setTextViewText(R.id.tv_title, "標題");    // 設置通知欄上標題
        remoteViews.setTextViewText(R.id.tv_artist, "藝術家");  // 設置通知欄上藝術家
        return remoteViews;
    }

4.Notification相關屬性說明

  • 4.1 PendingIntent說明
  • 4.1.1 PendingIntent基本說明
  • PendingIntent 是一種特殊的 Intent ,字面意思可以解釋爲延遲的 Intent ,用於在某個事件結束後執行特定的 Action 。從上面帶 Action 的通知也能驗證這一點,當用戶點擊通知時,纔會執行。
  • PendingIntent 是 Android 系統管理並持有的用於描述和獲取原始數據的對象的標誌(引用)。也就是說,即便創建該PendingIntent對象的進程被殺死了,這個PendingItent對象在其他進程中還是可用的。
    日常使用中的短信、鬧鐘等都用到了 PendingIntent。

  • 4.1.2 PendingIntent三種獲取方式
    //獲取一個用於啓動 Activity 的 PendingIntent 對象public static PendingIntent getActivity(Context context, int requestCode, Intent intent, int flags);
    //獲取一個用於啓動 Service 的 PendingIntent 對象public static PendingIntent getService(Context context, int requestCode, Intent intent, int flags);
    //獲取一個用於向 BroadcastReceiver 廣播的 PendingIntent 對象public static PendingIntent getBroadcast(Context context, int requestCode, Intent intent, int flags)
  • 4.1.3 PendingIntent具有幾種flag
    FLAG_CANCEL_CURRENT:如果當前系統中已經存在一個相同的 PendingIntent 對象,那麼就將先將已有的 PendingIntent 取消,然後重新生成一個 PendingIntent 對象。
    FLAG_NO_CREATE:如果當前系統中不存在相同的 PendingIntent 對象,系統將不會創建該 PendingIntent 對象而是直接返回 null 。
    FLAG_ONE_SHOT:該 PendingIntent 只作用一次。
    FLAG_UPDATE_CURRENT:如果系統中已存在該 PendingIntent 對象,那麼系統將保留該 PendingIntent 對象,但是會使用新的 Intent 來更新之前 PendingIntent 中的 Intent 對象數據,例如更新 Intent 中的 Extras 。
  • 4.2 創建返回棧PendingIntent
  • 4.2.1 添加返回棧代碼
    默認情況下,從通知啓動一個Activity,按返回鍵會回到主屏幕。
    但某些時候有按返回鍵仍然留在當前應用的需求,這就要用到TaskStackBuilder了。
    Notification.Builder mBuilder = new Notification.Builder(context)
                    .setSound(android.provider.Settings.System.DEFAULT_NOTIFICATION_URI)
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setContentTitle("廣播接受者標題,小楊")
                    .setContentText("廣播接受者內容,扯犢子")
                    .setAutoCancel(true);
    Log.i(TAG, "onReceive: intent" + intent.getClass().getName());
    Intent resultIntent = new Intent(context, MainActivity.class);
    TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
    //將該Activity添加爲棧頂
    stackBuilder.addParentStack(MainActivity.class);
    stackBuilder.addNextIntent(resultIntent);
    PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
    mBuilder.setContentIntent(resultPendingIntent);
    NotificationManager mNotificationManager = (NotificationManager)
            context.getSystemService(Context.NOTIFICATION_SERVICE);
    mNotificationManager.notify(1, mBuilder.build());
  • 4.3 注意要點
  • 如果用戶的手機使靜音模式,那麼設置鈴聲或者震動效果將會失效

5.部分源碼分析思考

  • 5.1 RemoteView是什麼?
  • 5.1.1 什麼是RemoteView?
  • 爲啥Notification不會設計成和普通View一樣的使用方式?理由很簡單!狀態欄不是單單由你的應用程序管理.狀態欄是由Android系統管理的.你需要顯示Notification就必須和系統打交道.必須通過Notification服務才能顯示你的Notification.所以設計成用一個Notification實例代表一個Notification,然後通過notificationManager.notify函數提交給Notification服務.
  • 5.1.2 Notification服務是什麼?是一個獨立的線程!
  • 又扯出一個問題.跨線程顯示View.該怎麼顯示?不是在本應用程序顯示View.這裏就要借用RemoteView.
  • RemoteView理解成對一個View的封裝,然後把RemoteView提交給其他線程.其他線程接收到RemoteView並且解析裏面View的信息把它顯示出來.
  • 5.1.3 在使用系統自帶的Notification系統會創建一個默認的RemoteView!
  • 系統默認使用R.layout.notification_template_material_base生產一個RemoteView.
    至於這裏的佈局是怎麼查到的,請看下面源碼分析

  • 5.2 查看源碼,瞭解Notification如何創建佈局
  • 5.2.1 首先看Notification中build代碼
    image
  • 5.2.2 然後看上圖中的createContentView()方法
    image
  • 5.2.3 然後看上圖中的createContentView()方法
    image

6.關於Android8.0通知欄適配

6.1 Android O(8.0)通知的改變

  • NotificationChannel是android8.0新增的特性,如果App的targetSDKVersion>=26,沒有設置channel通知渠道的話,就會導致通知無法展示。
  • Android O 引入了 通知渠道(Notification Channels),以提供統一的系統來幫助用戶管理通知,如果是針對 android O 爲目標平臺時,必須實現一個或者多個通知渠道,以向用戶顯示通知。比如聊天軟件,爲每個聊天組設置一個通知渠道,指定特定聲音、燈光等配置。

6.2 報錯內容和解決方案

  • 報錯內容:Failed to post notification on channel “null” Target Api is 26
  • 解決方案:
    • 第一種:臨時方案,google也考慮到適配問題,臨時兼容方案是targetSDKVersion低於26
    • 第二種:創建channel

6.3 最終解決方案

  • 6.3.1 創建NotificationChannel步驟

    • 創建NotificationChannel對象,指定Channel的id、name和通知的重要程度
    • 使用NotificationMannager的createNotificationChannel方法來添加Channel。
      
      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
      //android 8.0以上需要特殊處理,也就是targetSDKVersion爲26以上
      createNotificationChannel();
      }

    @TargetApi(Build.VERSION_CODES.O)
    private void createNotificationChannel() {
    NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT);
    channel.canBypassDnd();//是否繞過請勿打擾模式
    channel.enableLights(true);//閃光燈
    channel.setLockscreenVisibility(VISIBILITY_SECRET);//鎖屏顯示通知
    channel.setLightColor(Color.RED);//閃關燈的燈光顏色
    channel.canShowBadge();//桌面launcher的消息角標
    channel.enableVibration(true);//是否允許震動
    channel.getAudioAttributes();//獲取系統通知響鈴聲音的配置
    channel.getGroup();//獲取通知取到組
    channel.setBypassDnd(true);//設置可繞過 請勿打擾模式
    channel.setVibrationPattern(new long[]{100, 100, 200});//設置震動模式
    channel.shouldShowLights();//是否會有燈光
    getManager().createNotificationChannel(channel);
    }

    
    - 設置通知重要性級別
        - 該級別必須要在 NotificationChannel的構造函數中指定,總共要五個級別;範圍是從NotificationManager.IMPORTANCE_NONE(0) ~ NotificationManager.IMPORTANCE_HIGH(4)
        - 如果要支持 Android 7.1(API 25)及以下的設備,還得調用NotificationCompat 的 setPriority 方法來設置
  • 6.3.2 用戶通知級別
    • Android 8.0 及以上是使用NotificationManager.IMPORTANCE_,
    • Android 7.1 及以下是使用NotificationCompat.PRIORITY_它們都是定義的常量
    • image

6.4 封裝的代碼

  • 如下所示

    public class NotificationUtils extends ContextWrapper {
    
        public static final String CHANNEL_ID = "default";
        private static final String CHANNEL_NAME = "Default_Channel";
        private NotificationManager mManager;
        private int[] flags;
    
        public NotificationUtils(Context base) {
            super(base);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                //android 8.0以上需要特殊處理,也就是targetSDKVersion爲26以上
                createNotificationChannel();
            }
        }
    
        @TargetApi(Build.VERSION_CODES.O)
        private void createNotificationChannel() {
            //第一個參數:channel_id
            //第二個參數:channel_name
            //第三個參數:設置通知重要性級別
            //注意:該級別必須要在 NotificationChannel 的構造函數中指定,總共要五個級別;
            //範圍是從 NotificationManager.IMPORTANCE_NONE(0) ~ NotificationManager.IMPORTANCE_HIGH(4)
            NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME,
                    NotificationManager.IMPORTANCE_DEFAULT);
            channel.canBypassDnd();//是否繞過請勿打擾模式
            channel.enableLights(true);//閃光燈
            channel.setLockscreenVisibility(VISIBILITY_SECRET);//鎖屏顯示通知
            channel.setLightColor(Color.RED);//閃關燈的燈光顏色
            channel.canShowBadge();//桌面launcher的消息角標
            channel.enableVibration(true);//是否允許震動
            channel.getAudioAttributes();//獲取系統通知響鈴聲音的配置
            channel.getGroup();//獲取通知取到組
            channel.setBypassDnd(true);//設置可繞過 請勿打擾模式
            channel.setVibrationPattern(new long[]{100, 100, 200});//設置震動模式
            channel.shouldShowLights();//是否會有燈光
            getManager().createNotificationChannel(channel);
        }
    
        /**
         * 獲取創建一個NotificationManager的對象
         * @return                          NotificationManager對象
         */
        public NotificationManager getManager() {
            if (mManager == null) {
                mManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            }
            return mManager;
        }
    
        /**
         * 清空所有的通知
         */
        public void clearNotification(){
            getManager().cancelAll();
        }
    
        /**
         * 建議使用這個發送通知
         * 調用該方法可以發送通知
         * @param notifyId                  notifyId
         * @param title                     title
         * @param content                   content
         */
        public void sendNotification(int notifyId, String title, String content , int icon) {
            Notification build;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                //android 8.0以上需要特殊處理,也就是targetSDKVersion爲26以上
                //通知用到NotificationCompat()這個V4庫中的方法。但是在實際使用時發現書上的代碼已經過時並且Android8.0已經不支持這種寫法
                Notification.Builder builder = getChannelNotification(title, content, icon);
                build = builder.build();
            } else {
                NotificationCompat.Builder builder = getNotificationCompat(title, content, icon);
                build = builder.build();
            }
            if (flags!=null && flags.length>0){
                for (int a=0 ; a<flags.length ; a++){
                    build.flags |= flags[a];
                }
            }
            getManager().notify(notifyId, build);
        }
    
        /**
         * 調用該方法可以發送通知
         * @param notifyId                  notifyId
         * @param title                     title
         * @param content                   content
         */
        public void sendNotificationCompat(int notifyId, String title, String content , int icon) {
            NotificationCompat.Builder builder = getNotificationCompat(title, content, icon);
            Notification build = builder.build();
            if (flags!=null && flags.length>0){
                for (int a=0 ; a<flags.length ; a++){
                    build.flags |= flags[a];
                }
            }
            getManager().notify(notifyId, build);
        }
    
        private NotificationCompat.Builder getNotificationCompat(String title, String content, int icon) {
            NotificationCompat.Builder builder;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                builder = new NotificationCompat.Builder(getApplicationContext(), CHANNEL_ID);
            } else {
                //注意用下面這個方法,在8.0以上無法出現通知欄。8.0之前是正常的。這裏需要增強判斷邏輯
                builder = new NotificationCompat.Builder(getApplicationContext());
                builder.setPriority(PRIORITY_DEFAULT);
            }
            builder.setContentTitle(title);
            builder.setContentText(content);
            builder.setSmallIcon(icon);
            builder.setPriority(priority);
            builder.setOnlyAlertOnce(onlyAlertOnce);
            builder.setOngoing(ongoing);
            if (remoteViews!=null){
                builder.setContent(remoteViews);
            }
            if (intent!=null){
                builder.setContentIntent(intent);
            }
            if (ticker!=null && ticker.length()>0){
                builder.setTicker(ticker);
            }
            if (when!=0){
                builder.setWhen(when);
            }
            if (sound!=null){
                builder.setSound(sound);
            }
            if (defaults!=0){
                builder.setDefaults(defaults);
            }
            //點擊自動刪除通知
            builder.setAutoCancel(true);
            return builder;
        }
    
        @RequiresApi(api = Build.VERSION_CODES.O)
        private Notification.Builder getChannelNotification(String title, String content, int icon){
            Notification.Builder builder = new Notification.Builder(getApplicationContext(), CHANNEL_ID);
            Notification.Builder notificationBuilder = builder
                    //設置標題
                    .setContentTitle(title)
                    //消息內容
                    .setContentText(content)
                    //設置通知的圖標
                    .setSmallIcon(icon)
                    //讓通知左右滑的時候是否可以取消通知
                    .setOngoing(ongoing)
                    //設置優先級
                    .setPriority(priority)
                    //是否提示一次.true - 如果Notification已經存在狀態欄即使在調用notify函數也不會更新
                    .setOnlyAlertOnce(onlyAlertOnce)
                    .setAutoCancel(true);
            if (remoteViews!=null){
                //設置自定義view通知欄
                notificationBuilder.setContent(remoteViews);
            }
            if (intent!=null){
                notificationBuilder.setContentIntent(intent);
            }
            if (ticker!=null && ticker.length()>0){
                //設置狀態欄的標題
                notificationBuilder.setTicker(ticker);
            }
            if (when!=0){
                //設置通知時間,默認爲系統發出通知的時間,通常不用設置
                notificationBuilder.setWhen(when);
            }
            if (sound!=null){
                //設置sound
                notificationBuilder.setSound(sound);
            }
            if (defaults!=0){
                //設置默認的提示音
                notificationBuilder.setDefaults(defaults);
            }
            if (pattern!=null){
                //自定義震動效果
                notificationBuilder.setVibrate(pattern);
            }
            return notificationBuilder;
        }
    
        private boolean ongoing = false;
        private RemoteViews remoteViews = null;
        private PendingIntent intent = null;
        private String ticker = "";
        private int priority = Notification.PRIORITY_DEFAULT;
        private boolean onlyAlertOnce = false;
        private long when = 0;
        private Uri sound = null;
        private int defaults = 0;
        private long[] pattern = null;
    
        /**
         * 讓通知左右滑的時候是否可以取消通知
         * @param ongoing                   是否可以取消通知
         * @return
         */
        public NotificationUtils setOngoing(boolean ongoing){
            this.ongoing = ongoing;
            return this;
        }
    
        /**
         * 設置自定義view通知欄佈局
         * @param remoteViews               view
         * @return
         */
        public NotificationUtils setContent(RemoteViews remoteViews){
            this.remoteViews = remoteViews;
            return this;
        }
    
        /**
         * 設置內容點擊
         * @param intent                    intent
         * @return
         */
        public NotificationUtils setContentIntent(PendingIntent intent){
            this.intent = intent;
            return this;
        }
    
        /**
         * 設置狀態欄的標題
         * @param ticker                    狀態欄的標題
         * @return
         */
        public NotificationUtils setTicker(String ticker){
            this.ticker = ticker;
            return this;
        }
    
        /**
         * 設置優先級
         * 注意:
         * Android 8.0以及上,在 NotificationChannel 的構造函數中指定,總共要五個級別;
         * Android 7.1(API 25)及以下的設備,還得調用NotificationCompat 的 setPriority方法來設置
         *
         * @param priority                  優先級,默認是Notification.PRIORITY_DEFAULT
         * @return
         */
        public NotificationUtils setPriority(int priority){
            this.priority = priority;
            return this;
        }
    
        /**
         * 是否提示一次.true - 如果Notification已經存在狀態欄即使在調用notify函數也不會更新
         * @param onlyAlertOnce             是否只提示一次,默認是false
         * @return
         */
        public NotificationUtils setOnlyAlertOnce(boolean onlyAlertOnce){
            this.onlyAlertOnce = onlyAlertOnce;
            return this;
        }
    
        /**
         * 設置通知時間,默認爲系統發出通知的時間,通常不用設置
         * @param when                      when
         * @return
         */
        public NotificationUtils setWhen(long when){
            this.when = when;
            return this;
        }
    
        /**
         * 設置sound
         * @param sound                     sound
         * @return
         */
        public NotificationUtils setSound(Uri sound){
            this.sound = sound;
            return this;
        }
    
        /**
         * 設置默認的提示音
         * @param defaults                  defaults
         * @return
         */
        public NotificationUtils setDefaults(int defaults){
            this.defaults = defaults;
            return this;
        }
    
        /**
         * 自定義震動效果
         * @param pattern                  pattern
         * @return
         */
        public NotificationUtils setVibrate(long[] pattern){
            this.pattern = pattern;
            return this;
        }
    
        /**
         * 設置flag標籤
         * @param flags                     flags
         * @return
         */
        public NotificationUtils setFlags(int... flags){
            this.flags = flags;
            return this;
        }
    
    }

項目地址鏈接:https://github.com/yangchong211/YCNotification

關於其他內容介紹

01.關於博客彙總鏈接

02.關於我的博客

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章