Android Notification 詳解(一)——基本操作

版權(quán)聲明:本文為博主原創(chuàng)文章,未經(jīng)博主允許不得轉(zhuǎn)載。
微博:厲圣杰
源碼:AndroidDemo/Notification
文中如有紕漏,歡迎大家留言指出。

前幾天項(xiàng)目中有用到 Android 通知相關(guān)的內(nèi)容,索性把 Android Notification 相關(guān)的知識(shí)都看了一遍,稍作梳理,在此做個(gè)總結(jié),以備不時(shí)之需。

溫故而知新,可以為師矣~

下圖是我對(duì) Notification 做的思維導(dǎo)圖,也是本文的主要邏輯。
![Android Notification](http://odsdowehg.bkt.clouddn.com/Android Notification.png)

本文主要講述 Notification 的基本操作部分,進(jìn)階部分的內(nèi)容還在學(xué)習(xí)ing~

Notification 概述

Notification,是一種具有全局效果的通知,可以在系統(tǒng)的通知欄中顯示。當(dāng) APP 向系統(tǒng)發(fā)出通知時(shí),它將先以圖標(biāo)的形式顯示在通知欄中。用戶可以下拉通知欄查看通知的詳細(xì)信息。通知欄和抽屜式通知欄均是由系統(tǒng)控制,用戶可以隨時(shí)查看。下面兩張圖均是來(lái)自 Google 官方文檔。

notification_area

圖 1 .通知欄中的通知

notification_drawe

圖 2 .抽屜式通知欄中的通知

通知的目的是告知用戶 App 事件。在平時(shí)的使用中,通知主要有以下幾個(gè)作用:

  1. 顯示接收到短消息、及時(shí)消息等信息(如QQ、微信、新浪、短信)
  2. 顯示客戶端的推送消息,如廣告、優(yōu)惠、版本更新、推薦新聞等,常用的第三方 SDK 有: JPush個(gè)推信鴿網(wǎng)易云信(偏重 IM )阿里云推送
  3. 顯示正在進(jìn)行的事物,例如:后臺(tái)運(yùn)行的程序,如音樂(lè)播放進(jìn)度、下載進(jìn)度等

其中,前兩點(diǎn)可以歸結(jié)為與用戶交互,第三點(diǎn)是實(shí)時(shí)的任務(wù)提醒,但不可否認(rèn)的是,第三點(diǎn)也會(huì)與用戶交互。

Notification 作為 Android 重要的用戶界面組成部分,它有自己的設(shè)計(jì)指南。在 Android 5.0(Api level 21) 中引入的 Material Design 尤為重要。關(guān)于 Notification 的設(shè)計(jì)指南請(qǐng)參考 Notification Pattern

Notification 的概述就這么多,接下去就開(kāi)始講 Notification 的基本使用,中間會(huì)穿插 Notification 的基本 UI 、各個(gè)版本的區(qū)別、常見(jiàn)的通知效果以及自己在學(xué)習(xí)過(guò)程中踩到的坑。

Notification 的基本操作

Notification 的基本操作主要有創(chuàng)建、更新、取消這三種。一個(gè) Notification 的必要屬性有三項(xiàng),如果不設(shè)置則在運(yùn)行時(shí)會(huì)拋出異常:

  1. 小圖標(biāo),通過(guò) setSmallIcon() 方法設(shè)置
  2. 標(biāo)題,通過(guò) setContentTitle() 方法設(shè)置
  3. 內(nèi)容,通過(guò) setContentText() 方法設(shè)置

除了以上三項(xiàng),其它均為可選項(xiàng)。雖然如此,但還是應(yīng)該給 Notification 設(shè)置一個(gè) Action ,這樣就可以直接跳轉(zhuǎn)到 App 的某個(gè) Activity 、啟動(dòng)一個(gè) Service 或者發(fā)送一個(gè) Broadcast。否則,Notification 僅僅只能起到通知的效果,而不能與用戶交互。

當(dāng)系統(tǒng)接收到通知時(shí),可以通過(guò)震動(dòng)、響鈴、呼吸燈等多種方式進(jìn)行提醒。

創(chuàng)建 Notification

Notification 的創(chuàng)建主要涉及到 Notification.BuilderNotificationNotificationManager

  1. Notification.Builer : 使用建造者模式構(gòu)建 Notification 對(duì)象。由于 Notification.Builder 僅支持 Android 4.1及之后的版本,為了解決兼容性問(wèn)題, Google 在 Android Support v4 中加入了 NotificationCompat.Builder 類。對(duì)于某些在 Android 4.1 之后才特性,即使 NotificationCompat.Builder 支持該方法,在之前的版本中也不能運(yùn)行。點(diǎn)我 查看更多關(guān)于 Notification 兼容性問(wèn)題處理。文中使用的都是 NotificationCompat。
  2. Notification : 通知對(duì)應(yīng)類,保存通知相關(guān)的數(shù)據(jù)。NotificationManager 向系統(tǒng)發(fā)送通知時(shí)會(huì)用到。
  3. NotificationManager : NotificationManager 是通知管理類,它是一個(gè)系統(tǒng)服務(wù)。調(diào)用 NotificationManager 的 notify() 方法可以向系統(tǒng)發(fā)送通知。

獲取 NotificationManager 對(duì)象:

NotificationManager mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

前面講到,Notification 有三個(gè)必要屬性。下面,我們就來(lái)創(chuàng)建一個(gè)簡(jiǎn)單的 Notification 。主要有以下三步:

  1. 獲取 NotificationManager 實(shí)例
  2. 實(shí)例化 NotificationCompat.Builder 并設(shè)置相關(guān)屬性
  3. 通過(guò) builder.build() 方法生成 Notification 對(duì)象,并發(fā)送通知
private void sendNotification() {
   //獲取NotificationManager實(shí)例
   NotificationManager notifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
   //實(shí)例化NotificationCompat.Builde并設(shè)置相關(guān)屬性
   NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
           //設(shè)置小圖標(biāo)
           .setSmallIcon(R.mipmap.icon_fab_repair)
           //設(shè)置通知標(biāo)題
           .setContentTitle("最簡(jiǎn)單的Notification")
           //設(shè)置通知內(nèi)容
           .setContentText("只有小圖標(biāo)、標(biāo)題、內(nèi)容")
           //設(shè)置通知時(shí)間,默認(rèn)為系統(tǒng)發(fā)出通知的時(shí)間,通常不用設(shè)置
           //.setWhen(System.currentTimeMillis());
   //通過(guò)builder.build()方法生成Notification對(duì)象,并發(fā)送通知,id=1
   notifyManager.notify(1, builder.build());
}

以上代碼是對(duì) Android 3.0 及之后的版本而言(包括使用 Support Library),對(duì)于 Android 3.0 之前的版本,主要使用 new Notification() 方法來(lái)創(chuàng)建 Notification 對(duì)象,本文不對(duì)此方式做任何講解,代碼如下:

NotificationManager mNotifyMgr = 
      (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
PendingIntent contentIntent = PendingIntent.getActivity(
      this, 0, new Intent(this, ResultActivity.class), 0);

Notification notification = new Notification(icon, tickerText, when);
notification.setLatestEventInfo(this, title, content, contentIntent);

mNotifyMgr.notify(NOTIFICATIONS_ID, notification);

補(bǔ)充

  • Android Support Library包的區(qū)別
Android Support v4:這個(gè)包是為了照顧1.6及更高版本而設(shè)計(jì)的,這個(gè)包是使用最廣泛的。

Android Support v7:這個(gè)包是為了考慮照顧2.1及以上版本而設(shè)計(jì)的,但不包含更低,故如果不考慮1.6,我們可以采用再加上這個(gè)包,另外注意,v7是要依賴v4這個(gè)包的,即,兩個(gè)得同時(shí)被包含。

Android Support v13:這個(gè)包的設(shè)計(jì)是為了android 3.2及更高版本的,一般我們都不常用,平板開(kāi)發(fā)中能用到。
  • Notification 中的元素。在 Android N(24) 中, Google 對(duì) Notification 的 UI 進(jìn)行了修改。下圖是 Android M 和 Android N 的對(duì)比。
    ![屏幕快照 2016-10-17 上午10.33.40](http://odsdowehg.bkt.clouddn.com/屏幕快照 2016-10-17 上午10.33.40.png)
  • 關(guān)于 setSmallIcon() 與 setLargeIcon()。在 NotificationCompat.Builder 中有設(shè)置通知的大小圖標(biāo)的兩個(gè)方法。這兩個(gè)方法有什么區(qū)別呢?當(dāng) setSmallIcon() 與 setLargeIcon() 同時(shí)存在時(shí), smallIcon 顯示在通知的右下角, largeIcon 顯示在左側(cè);當(dāng)只設(shè)置 setSmallIcon() 時(shí), smallIcon 顯示在左側(cè)。看下圖你就明白了。對(duì)于部分 ROM ,可能修改過(guò)源碼,如 MIUI 上通知的大圖標(biāo)和小圖標(biāo)是沒(méi)有區(qū)別的。
    ![屏幕快照 2016-10-17 上午10.38.05](http://odsdowehg.bkt.clouddn.com/屏幕快照 2016-10-17 上午10.38.05.png)

Google 官方是這么解釋 setSmallIcon() 這個(gè)方法的:

Set the small icon resource, which will be used to represent the notification in the status bar. The platform template for the expanded view will draw this icon in the left, unless a large icon has also been specified, in which case the small icon will be moved to the right-hand side.

給 Notification 設(shè)置 Action

在前一章節(jié) 創(chuàng)建 Notification 中發(fā)送的通知并不具備與用戶交互的能力,這是因?yàn)槲覀儾](méi)有給 Notification 設(shè)置 Action 。在這一節(jié),我們就來(lái)講講如何給 Notification 設(shè)置 Action 。這里,我們來(lái)實(shí)現(xiàn)一個(gè)點(diǎn)擊 Notification 跳轉(zhuǎn)到 MainActivity 的效果。代碼如下:

/**
* 發(fā)送一個(gè)點(diǎn)擊跳轉(zhuǎn)到MainActivity的消息
*/
private void sendSimplestNotificationWithAction() {
   //獲取PendingIntent
   Intent mainIntent = new Intent(this, MainActivity.class);
   PendingIntent mainPendingIntent = PendingIntent.getActivity(this, 0, mainIntent, PendingIntent.FLAG_UPDATE_CURRENT);
   //創(chuàng)建 Notification.Builder 對(duì)象
   NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
           .setSmallIcon(R.mipmap.ic_launcher)
           //點(diǎn)擊通知后自動(dòng)清除
           .setAutoCancel(true)
           .setContentTitle("我是帶Action的Notification")
           .setContentText("點(diǎn)我會(huì)打開(kāi)MainActivity")
           .setContentIntent(mainPendingIntent);
   //發(fā)送通知
   mNotifyManager.notify(3, builder.build());
}

相比發(fā)送最簡(jiǎn)單的通知,發(fā)送具有 Action 的通知多了創(chuàng)建 Intent 、 PendingIntent 和 setContentIntent() 這幾步。
不難看出, PendingIntent 才是重點(diǎn),那么, PendingIntent 是什么呢?

PendingIntent

如果您了解 PendingIntent ,請(qǐng)直接跳過(guò)本節(jié)。

PendingIntent 是一種特殊的 Intent ,字面意思可以解釋為延遲的 Intent ,用于在某個(gè)事件結(jié)束后執(zhí)行特定的 Action 。從上面帶 Action 的通知也能驗(yàn)證這一點(diǎn),當(dāng)用戶點(diǎn)擊通知時(shí),才會(huì)執(zhí)行。
PendingIntent 是 Android 系統(tǒng)管理并持有的用于描述和獲取原始數(shù)據(jù)的對(duì)象的標(biāo)志(引用)。也就是說(shuō),即便創(chuàng)建該P(yáng)endingIntent對(duì)象的進(jìn)程被殺死了,這個(gè)PendingItent對(duì)象在其他進(jìn)程中還是可用的
日常使用中的短信、鬧鐘等都用到了 PendingIntent。

PendingIntent 主要可以通過(guò)以下三種方式獲取:

//獲取一個(gè)用于啟動(dòng) Activity 的 PendingIntent 對(duì)象
public static PendingIntent getActivity(Context context, int requestCode, Intent intent, int flags);

//獲取一個(gè)用于啟動(dòng) Service 的 PendingIntent 對(duì)象
public static PendingIntent getService(Context context, int requestCode, Intent intent, int flags);

//獲取一個(gè)用于向 BroadcastReceiver 廣播的 PendingIntent 對(duì)象
public static PendingIntent getBroadcast(Context context, int requestCode, Intent intent, int flags)

PendingIntent 具有以下幾種 flag:

FLAG_CANCEL_CURRENT:如果當(dāng)前系統(tǒng)中已經(jīng)存在一個(gè)相同的 PendingIntent 對(duì)象,那么就將先將已有的 PendingIntent 取消,然后重新生成一個(gè) PendingIntent 對(duì)象。

FLAG_NO_CREATE:如果當(dāng)前系統(tǒng)中不存在相同的 PendingIntent 對(duì)象,系統(tǒng)將不會(huì)創(chuàng)建該 PendingIntent 對(duì)象而是直接返回 null 。

FLAG_ONE_SHOT:該 PendingIntent 只作用一次。

FLAG_UPDATE_CURRENT:如果系統(tǒng)中已存在該 PendingIntent 對(duì)象,那么系統(tǒng)將保留該 PendingIntent 對(duì)象,但是會(huì)使用新的 Intent 來(lái)更新之前 PendingIntent 中的 Intent 對(duì)象數(shù)據(jù),例如更新 Intent 中的 Extras 。

更新 Notification

更新通知很簡(jiǎn)單,只需要再次發(fā)送相同 ID 的通知即可,如果之前的通知還未被取消,則會(huì)直接更新該通知相關(guān)的屬性;如果之前的通知已經(jīng)被取消,則會(huì)重新創(chuàng)建一個(gè)新通知。

更新通知跟發(fā)送通知使用相同的方式。詳見(jiàn)上節(jié):創(chuàng)建 Notification

取消 Notification

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

  1. 點(diǎn)擊通知欄的清除按鈕,會(huì)清除所有可清除的通知
  2. 設(shè)置了 setAutoCancel() 或 FLAG_AUTO_CANCEL 的通知,點(diǎn)擊該通知時(shí)會(huì)清除它
  3. 通過(guò) NotificationManager 調(diào)用 cancel(int id) 方法清除指定 ID 的通知
  4. 通過(guò) NotificationManager 調(diào)用 cancel(String tag, int id) 方法清除指定 TAG 和 ID 的通知
  5. 通過(guò) NotificationManager 調(diào)用 cancelAll() 方法清除所有該應(yīng)用之前發(fā)送的通知

如果你是通過(guò) NotificationManager.notify(String tag, int id, Notification notify) 方法創(chuàng)建的通知,那么只能通過(guò) NotificationManager.cancel(String tag, int id) 方法才能清除對(duì)應(yīng)的通知,調(diào)用NotificationManager.cancel(int id) 無(wú)效。

關(guān)于 Notification 的基本操作代碼如下,布局文件代碼這就不貼了。我是 Demo 傳送門

/**
 * 為了方便,大部分通知都沒(méi)設(shè)置對(duì)應(yīng)的Action,即PendingIntent
 * 除了sendFlagAutoCancelNotification()方法
 */
public class SimpleNotificationActivity extends Activity implements View.OnClickListener {

    //Notification.FLAG_FOREGROUND_SERVICE    //表示正在運(yùn)行的服務(wù)
    public static final String NOTIFICATION_TAG = "littlejie";
    public static final int DEFAULT_NOTIFICATION_ID = 1;

    private NotificationManager mNotificationManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_simple_notification);

        findViewById(R.id.btn_remove_all_notification).setOnClickListener(this);
        findViewById(R.id.btn_send_notification).setOnClickListener(this);
        findViewById(R.id.btn_remove_notification).setOnClickListener(this);
        findViewById(R.id.btn_send_notification_with_tag).setOnClickListener(this);
        findViewById(R.id.btn_remove_notification_with_tag).setOnClickListener(this);
        findViewById(R.id.btn_send_ten_notification).setOnClickListener(this);
        findViewById(R.id.btn_send_flag_no_clear_notification).setOnClickListener(this);
        findViewById(R.id.btn_send_flag_ongoing_event_notification).setOnClickListener(this);
        findViewById(R.id.btn_send_flag_auto_cancecl_notification).setOnClickListener(this);

        mNotificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_remove_all_notification:
                //移除當(dāng)前 Context 下所有 Notification,包括 FLAG_NO_CLEAR 和 FLAG_ONGOING_EVENT
                mNotificationManager.cancelAll();
                break;
            case R.id.btn_send_notification:
                //發(fā)送一個(gè) Notification,此處 ID = 1
                sendNotification();
                break;
            case R.id.btn_remove_notification:
                //移除 ID = 1 的 Notification,注意:該方法只針對(duì)當(dāng)前 Context。
                mNotificationManager.cancel(DEFAULT_NOTIFICATION_ID);
                break;
            case R.id.btn_send_notification_with_tag:
                //發(fā)送一個(gè) ID = 1 并且 TAG = littlejie 的 Notification
                //注意:此處發(fā)送的通知與 sendNotification() 發(fā)送的通知并不沖突
                //因?yàn)榇颂幍?Notification 帶有 TAG
                sendNotificationWithTag();
                break;
            case R.id.btn_remove_notification_with_tag:
                //移除一個(gè) ID = 1 并且 TAG = littlejie 的 Notification
                //注意:此處移除的通知與 NotificationManager.cancel(int id) 移除通知并不沖突
                //因?yàn)榇颂幍?Notification 帶有 TAG
                mNotificationManager.cancel(NOTIFICATION_TAG, DEFAULT_NOTIFICATION_ID);
                break;
            case R.id.btn_send_ten_notification:
                //連續(xù)發(fā)十條 Notification
                sendTenNotifications();
                break;
            case R.id.btn_send_flag_no_clear_notification:
                //發(fā)送 ID = 1, flag = FLAG_NO_CLEAR 的 Notification
                //下面兩個(gè) Notification 的 ID 都為 1,會(huì)發(fā)現(xiàn) ID 相等的 Notification 會(huì)被最新的替換掉
                sendFlagNoClearNotification();
                break;
            case R.id.btn_send_flag_auto_cancecl_notification:
                sendFlagOngoingEventNotification();
                break;
            case R.id.btn_send_flag_ongoing_event_notification:
                sendFlagAutoCancelNotification();
                break;
        }
    }

    /**
     * 發(fā)送最簡(jiǎn)單的通知,該通知的ID = 1
     */
    private void sendNotification() {
        //這里使用 NotificationCompat 而不是 Notification ,因?yàn)?Notification 需要 API 16 才能使用
        //NotificationCompat 存在于 V4 Support Library
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentTitle("Send Notification")
                .setContentText("Hi,My id is 1");
        mNotificationManager.notify(DEFAULT_NOTIFICATION_ID, builder.build());
    }

    /**
     * 使用notify(String tag, int id, Notification notification)方法發(fā)送通知
     * 移除對(duì)應(yīng)通知需使用 cancel(String tag, int id)
     */
    private void sendNotificationWithTag() {
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentTitle("Send Notification With Tag")
                .setContentText("Hi,My id is 1,tag is " + NOTIFICATION_TAG);
        mNotificationManager.notify(NOTIFICATION_TAG, DEFAULT_NOTIFICATION_ID, builder.build());
    }

    /**
     * 循環(huán)發(fā)送十個(gè)通知
     */
    private void sendTenNotifications() {
        for (int i = 0; i < 10; i++) {
            NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setContentTitle("Send Notification Batch")
                    .setContentText("Hi,My id is " + i);
            mNotificationManager.notify(i, builder.build());
        }
    }

    /**
     * 設(shè)置FLAG_NO_CLEAR
     * 該 flag 表示該通知不能被狀態(tài)欄的清除按鈕給清除掉,也不能被手動(dòng)清除,但能通過(guò) cancel() 方法清除
     * Notification.flags屬性可以通過(guò) |= 運(yùn)算疊加效果
     */
    private void sendFlagNoClearNotification() {
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentTitle("Send Notification Use FLAG_NO_CLEAR")
                .setContentText("Hi,My id is 1,i can't be clear.");
        Notification notification = builder.build();
        //設(shè)置 Notification 的 flags = FLAG_NO_CLEAR
        //FLAG_NO_CLEAR 表示該通知不能被狀態(tài)欄的清除按鈕給清除掉,也不能被手動(dòng)清除,但能通過(guò) cancel() 方法清除
        //flags 可以通過(guò) |= 運(yùn)算疊加效果
        notification.flags |= Notification.FLAG_NO_CLEAR;
        mNotificationManager.notify(DEFAULT_NOTIFICATION_ID, notification);
    }

    /**
     * 設(shè)置FLAG_AUTO_CANCEL
     * 該 flag 表示用戶單擊通知后自動(dòng)消失
     */
    private void sendFlagAutoCancelNotification() {
        //設(shè)置一個(gè)Intent,不然點(diǎn)擊通知不會(huì)自動(dòng)消失
        Intent resultIntent = new Intent(this, MainActivity.class);
        PendingIntent resultPendingIntent = PendingIntent.getActivity(
                this, 0, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentTitle("Send Notification Use FLAG_AUTO_CLEAR")
                .setContentText("Hi,My id is 1,i can be clear.")
                .setContentIntent(resultPendingIntent);
        Notification notification = builder.build();
        //設(shè)置 Notification 的 flags = FLAG_NO_CLEAR
        //FLAG_AUTO_CANCEL 表示該通知能被狀態(tài)欄的清除按鈕給清除掉
        //等價(jià)于 builder.setAutoCancel(true);
        notification.flags |= Notification.FLAG_AUTO_CANCEL;
        mNotificationManager.notify(DEFAULT_NOTIFICATION_ID, notification);
    }

    /**
     * 設(shè)置FLAG_ONGOING_EVENT
     * 該 flag 表示發(fā)起正在運(yùn)行事件(活動(dòng)中)
     */
    private void sendFlagOngoingEventNotification() {
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentTitle("Send Notification Use FLAG_ONGOING_EVENT")
                .setContentText("Hi,My id is 1,i can't be clear.");
        Notification notification = builder.build();
        //設(shè)置 Notification 的 flags = FLAG_NO_CLEAR
        //FLAG_ONGOING_EVENT 表示該通知通知放置在正在運(yùn)行,不能被手動(dòng)清除,但能通過(guò) cancel() 方法清除
        //等價(jià)于 builder.setOngoing(true);
        notification.flags |= Notification.FLAG_ONGOING_EVENT;
        mNotificationManager.notify(DEFAULT_NOTIFICATION_ID, notification);
    }    
}

設(shè)置 Notification 的通知效果

前面講了 Notification 的創(chuàng)建、更新和取消,以及給 Notification 設(shè)置 Action 等基本操作。那么,我怎么給 Notification 設(shè)置諸如震動(dòng)、鈴聲、呼吸燈等效果呢?別急,接下來(lái)馬上就會(huì)告訴你怎么給 Notification 添加效果。

Notification 有震動(dòng)、響鈴、呼吸燈三種響鈴效果,可以通過(guò) setDefaults(int defualts) 方法來(lái)設(shè)置。 Default 屬性有以下四種,一旦設(shè)置了 Default 效果,自定義的效果就會(huì)失效。樓主在這里踩了坑,愣是調(diào)了半天沒(méi)找到為什么自定義效果會(huì)消失,忘大家慎之。

//設(shè)置系統(tǒng)默認(rèn)提醒效果,一旦設(shè)置默認(rèn)提醒效果,則自定義的提醒效果會(huì)全部失效。具體可看源碼
//添加默認(rèn)震動(dòng)效果,需要申請(qǐng)震動(dòng)權(quán)限
//<uses-permission android:name="android.permission.VIBRATE" />
Notification.DEFAULT_VIBRATE

//添加系統(tǒng)默認(rèn)聲音效果,設(shè)置此值后,調(diào)用setSound()設(shè)置自定義聲音無(wú)效
Notification.DEFAULT_SOUND

//添加默認(rèn)呼吸燈效果,使用時(shí)須與 Notification.FLAG_SHOW_LIGHTS 結(jié)合使用,否則無(wú)效
Notification.DEFAULT_LIGHTS

//添加上述三種默認(rèn)提醒效果
Notification.DEFAULT_ALL

除了以上幾種設(shè)置 Notification 默認(rèn)通知效果,還可以通過(guò)以下幾種 FLAG 設(shè)置通知效果。

//提醒效果常用 Flag
//三色燈提醒,在使用三色燈提醒時(shí)候必須加該標(biāo)志符
Notification.FLAG_SHOW_LIGHTS

//發(fā)起正在運(yùn)行事件(活動(dòng)中)
Notification.FLAG_ONGOING_EVENT

//讓聲音、振動(dòng)無(wú)限循環(huán),直到用戶響應(yīng) (取消或者打開(kāi))
Notification.FLAG_INSISTENT

//發(fā)起Notification后,鈴聲和震動(dòng)均只執(zhí)行一次
Notification.FLAG_ONLY_ALERT_ONCE

//用戶單擊通知后自動(dòng)消失
Notification.FLAG_AUTO_CANCEL

//只有調(diào)用NotificationManager.cancel()時(shí)才會(huì)清除
Notification.FLAG_NO_CLEAR

//表示正在運(yùn)行的服務(wù)
Notification.FLAG_FOREGROUND_SERVICE

Notification 通知效果的設(shè)置方式及注意事項(xiàng)全部在代碼中,核心代碼如下:

/**
* 最普通的通知效果
*/
private void showNotifyOnlyText() {
   NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
           .setSmallIcon(R.mipmap.ic_launcher)
           .setLargeIcon(mLargeIcon)
           .setContentTitle("我是只有文字效果的通知")
           .setContentText("我沒(méi)有鈴聲、震動(dòng)、呼吸燈,但我就是一個(gè)通知");
   mManager.notify(1, builder.build());
}

/**
* 展示有自定義鈴聲效果的通知
* 補(bǔ)充:使用系統(tǒng)自帶的鈴聲效果:Uri.withAppendedPath(Audio.Media.INTERNAL_CONTENT_URI, "6");
*/
private void showNotifyWithRing() {
   NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
           .setSmallIcon(R.mipmap.ic_launcher)
           .setContentTitle("我是伴有鈴聲效果的通知")
           .setContentText("美妙么?安靜聽(tīng)~")
           //調(diào)用系統(tǒng)默認(rèn)響鈴,設(shè)置此屬性后setSound()會(huì)無(wú)效
           //.setDefaults(Notification.DEFAULT_SOUND)
           //調(diào)用系統(tǒng)多媒體褲內(nèi)的鈴聲
           //.setSound(Uri.withAppendedPath(MediaStore.Audio.Media.INTERNAL_CONTENT_URI,"2"));
           //調(diào)用自己提供的鈴聲,位于 /res/values/raw 目錄下
           .setSound(Uri.parse("android.resource://com.littlejie.notification/" + R.raw.sound));
   //另一種設(shè)置鈴聲的方法
   //Notification notify = builder.build();
   //調(diào)用系統(tǒng)默認(rèn)鈴聲
   //notify.defaults = Notification.DEFAULT_SOUND;
   //調(diào)用自己提供的鈴聲
   //notify.sound = Uri.parse("android.resource://com.littlejie.notification/"+R.raw.sound);
   //調(diào)用系統(tǒng)自帶的鈴聲
   //notify.sound = Uri.withAppendedPath(MediaStore.Audio.Media.INTERNAL_CONTENT_URI,"2");
   //mManager.notify(2,notify);
   mManager.notify(2, builder.build());
}

/**
* 展示有震動(dòng)效果的通知,需要在AndroidManifest.xml中申請(qǐng)震動(dòng)權(quán)限
* <uses-permission android:name="android.permission.VIBRATE" />
* 補(bǔ)充:測(cè)試震動(dòng)的時(shí)候,手機(jī)的模式一定要調(diào)成鈴聲+震動(dòng)模式,否則你是感受不到震動(dòng)的
*/
private void showNotifyWithVibrate() {
   //震動(dòng)也有兩種設(shè)置方法,與設(shè)置鈴聲一樣,在此不再贅述
   long[] vibrate = new long[]{0, 500, 1000, 1500};
   NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
           .setSmallIcon(R.mipmap.ic_launcher)
           .setContentTitle("我是伴有震動(dòng)效果的通知")
           .setContentText("顫抖吧,凡人~")
           //使用系統(tǒng)默認(rèn)的震動(dòng)參數(shù),會(huì)與自定義的沖突
           //.setDefaults(Notification.DEFAULT_VIBRATE)
           //自定義震動(dòng)效果
           .setVibrate(vibrate);
   //另一種設(shè)置震動(dòng)的方法
   //Notification notify = builder.build();
   //調(diào)用系統(tǒng)默認(rèn)震動(dòng)
   //notify.defaults = Notification.DEFAULT_VIBRATE;
   //調(diào)用自己設(shè)置的震動(dòng)
   //notify.vibrate = vibrate;
   //mManager.notify(3,notify);
   mManager.notify(3, builder.build());
}

/**
* 顯示帶有呼吸燈效果的通知,但是不知道為什么,自己這里測(cè)試沒(méi)成功
*/
private void showNotifyWithLights() {
   final NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
           .setSmallIcon(R.mipmap.ic_launcher)
           .setContentTitle("我是帶有呼吸燈效果的通知")
           .setContentText("一閃一閃亮晶晶~")
           //ledARGB 表示燈光顏色、 ledOnMS 亮持續(xù)時(shí)間、ledOffMS 暗的時(shí)間
           .setLights(0xFF0000, 3000, 3000);
   Notification notify = builder.build();
   //只有在設(shè)置了標(biāo)志符Flags為Notification.FLAG_SHOW_LIGHTS的時(shí)候,才支持呼吸燈提醒。
   notify.flags = Notification.FLAG_SHOW_LIGHTS;
   //設(shè)置lights參數(shù)的另一種方式
   //notify.ledARGB = 0xFF0000;
   //notify.ledOnMS = 500;
   //notify.ledOffMS = 5000;
   //使用handler延遲發(fā)送通知,因?yàn)檫B接usb時(shí),呼吸燈一直會(huì)亮著
   Handler handler = new Handler();
   handler.postDelayed(new Runnable() {
       @Override
       public void run() {
           mManager.notify(4, builder.build());
       }
   }, 10000);
}

/**
* 顯示帶有默認(rèn)鈴聲、震動(dòng)、呼吸燈效果的通知
* 如需實(shí)現(xiàn)自定義效果,請(qǐng)參考前面三個(gè)例子
*/
private void showNotifyWithMixed() {
   NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
           .setSmallIcon(R.mipmap.ic_launcher)
           .setContentTitle("我是有鈴聲+震動(dòng)+呼吸燈效果的通知")
           .setContentText("我是最棒的~")
           //等價(jià)于setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_LIGHTS | Notification.DEFAULT_VIBRATE);
           .setDefaults(Notification.DEFAULT_ALL);
   mManager.notify(5, builder.build());
}

/**
* 通知無(wú)限循環(huán),直到用戶取消或者打開(kāi)通知欄(其實(shí)觸摸就可以了),效果與FLAG_ONLY_ALERT_ONCE相反
* 注:這里沒(méi)有給Notification設(shè)置PendingIntent,也就是說(shuō)該通知無(wú)法響應(yīng),所以只能手動(dòng)取消
*/
private void showInsistentNotify() {
   NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
           .setSmallIcon(R.mipmap.ic_launcher)
           .setContentTitle("我是一個(gè)死循環(huán),除非你取消或者響應(yīng)")
           .setContentText("啦啦啦~")
           .setDefaults(Notification.DEFAULT_ALL);
   Notification notify = builder.build();
   notify.flags |= Notification.FLAG_INSISTENT;
   mManager.notify(6, notify);
}

/**
* 通知只執(zhí)行一次,與默認(rèn)的效果一樣
*/
private void showAlertOnceNotify() {
   NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
           .setSmallIcon(R.mipmap.ic_launcher)
           .setContentTitle("仔細(xì)看,我就執(zhí)行一遍")
           .setContentText("好了,已經(jīng)一遍了~")
           .setDefaults(Notification.DEFAULT_ALL);
   Notification notify = builder.build();
   notify.flags |= Notification.FLAG_ONLY_ALERT_ONCE;
   mManager.notify(7, notify);
}

/**
* 清除所有通知
*/
private void clearNotify() {
   mManager.cancelAll();
}

至此, Notification 的基本操作都已經(jīng)講完了,發(fā)送一個(gè)帶有自定義效果的簡(jiǎn)單通知已經(jīng)不在話下。接下去,我們會(huì)講 Notification 的一些高級(jí)操作。快上車,沒(méi)時(shí)間解釋了~

補(bǔ)充:當(dāng)用戶點(diǎn)擊通知欄的時(shí)候,正在進(jìn)行的通知,比如 Notification 的 flags = Notification.FLAG_INSISTENT ,那么相當(dāng)于用戶響應(yīng)了該通知,后面的 Demo 中會(huì)給出具體的代碼

參考

  1. Android Patterns——Notification
  2. Android User Interface——Notification
  3. 全面了解Android Notification
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容