1. 程式人生 > >Notification通知欄

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.關於我的部落格