全面了解Android Notification

最近時不時地有人問我這樣或那樣的通知如何實現(xiàn)吩屹,所以本文將根據(jù)個人經(jīng)驗對Notification做個總結(jié),以供參考肆捕!

什么是通知(Notification)

通知是一個可以在應用程序正常的用戶界面之外顯示給用戶的消息。
通知發(fā)出時,它首先出現(xiàn)在狀態(tài)欄的通知區(qū)域中额衙,用戶打開通知抽屜可查看通知詳情。通知區(qū)域和通知抽屜都是用戶可以隨時查看的系統(tǒng)控制區(qū)域。

作為安卓用戶界面的重要組成部分窍侧,通知有自己的設計指南县踢。在Android 5.0(API level 21)中引入的 Material Design 的變化是特別重要的,更多信息請閱讀 通知設計指南伟件。

如何創(chuàng)建通知

隨著Android系統(tǒng)不斷升級硼啤,Notification的創(chuàng)建方式也隨之變化,主要變化如下:

Android 3.0之前

Android 3.0 (API level 11)之前斧账,使用new Notification()方式創(chuàng)建通知:

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);

Android 3.0 (API level 11)及更高版本

Android 3.0開始棄用new Notification()方式谴返,改用Notification.Builder()來創(chuàng)建通知:

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

Notification notification = new Notification.Builder(this)
            .setSmallIcon(R.drawable.notification_icon)
            .setContentTitle("My notification")
            .setContentText("Hello World!")
            .setContentIntent(contentIntent)
            .build();// getNotification()

mNotifyMgr.notify(NOTIFICATIONS_ID, notification);

這里需要注意: "build()" 是Androdi 4.1(API level 16)加入的,用以替代
"getNotification()"咧织。API level 16開始棄用"getNotification()"

兼容Android 3.0之前的版本

為了兼容API level 11之前的版本嗓袱,v4 Support Library中提供了
NotificationCompat.Builder()這個替代方法。它與Notification.Builder()類似习绢,二者沒有太大區(qū)別渠抹。

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

NotificationCompat.Builder mBuilder = 
      new NotificationCompat.Builder(this)
            .setSmallIcon(R.drawable.notification_icon)
            .setContentTitle("My notification")
            .setContentText("Hello World!")
            .setContentIntent(contentIntent);

mNotifyMgr.notify(NOTIFICATIONS_ID, mBuilder.build());

注:除特別說明外,本文將根據(jù) NotificationCompat.Builder() 展開解析闪萄,
Notification.Builder()類似梧却。

通知基本用法

通知的必要屬性

一個通知必須包含以下三項屬性:

  • 小圖標,對應 setSmallIcon()
  • 通知標題败去,對應 setContentTitle()
  • 詳細信息放航,對應 setContentText()

其他屬性均為可選項,更多屬性方法請參考NotificationCompat.Builder为迈。

盡管其他都是可選的三椿,但一般都會為通知添加至少一個動作(Action),這個動作可以是跳轉(zhuǎn)到Activity葫辐、啟動一個Service或發(fā)送一個Broadcas等搜锰。 通過以下方式為通知添加動作:

  • 使用PendingIntent
  • 通過大視圖通知的 Action Button //僅支持Android 4.1 (API level 16)及更高版本,稍后會介紹

創(chuàng)建通知

1耿战、實例化一個NotificationCompat.Builder對象

NotificationCompat.Builder mBuilder = 
      new NotificationCompat.Builder(this)
            .setSmallIcon(R.drawable.notification_icon)
            .setContentTitle("My notification")
            .setContentText("Hello World!");

NotificationCompat.Builder自動設置的默認值:

  • priority: PRIORITY_DEFAULT
  • when: System.currentTimeMillis()
  • audio stream: STREAM_DEFAULT

2蛋叼、定義并設置一個通知動作(Action)

Intent resultIntent = new Intent(this, ResultActivity.class);
PendingIntent resultPendingIntent = PendingIntent.getActivity(
            this, 0, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(resultPendingIntent);

3、生成Notification對象

Notificatioin notification = mBuilder.build();

4剂陡、使用NotificationManager發(fā)送通知

// Sets an ID for the notification
int mNotificationId = 001;

// Gets an instance of the NotificationManager service
NotificationManager mNotifyMgr = 
      (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

// Builds the notification and issues it.
mNotifyMgr.notify(mNotificationId, notification);

更新通知

更新通知很簡單狈涮,只需再次發(fā)送相同ID的通知即可,如果之前的通知依然存在則會更新通知屬性鸭栖,如果之前通知不存在則重新創(chuàng)建歌馍。
示例代碼:

NotificationManager mNotifyMgr = 
      (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
// Sets an ID for the notification, so it can be updated
int notifyID = 1;
NotificationCompat.Builder mNotifyBuilder = 
      new NotificationCompat.Builder(this)
          .setContentTitle("New Message")
          .setContentText("You've received new messages.")
          .setSmallIcon(R.drawable.ic_notify_status);

int numMessages = 0;
...
    mNotifyBuilder.setContentText("new content text")
            .setNumber(++numMessages);
    mNotifyMgr.notify(notifyID, mNotifyBuilder.build());
...

取消通知

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

  • 點擊通知欄的清除按鈕,會清除所有可清除的通知
  • 設置了 setAutoCancel() 或 FLAG_AUTO_CANCEL的通知晕鹊,點擊該通知時會清除它
  • 通過 NotificationManager 調(diào)用 cancel() 方法清除指定ID的通知
  • 通過 NotificationManager 調(diào)用 cancelAll() 方法清除所有該應用之前發(fā)送的通知

通知類型

大視圖通知

通知有兩種視圖:普通視圖和大視圖松却。
普通視圖:


大視圖:

默認情況下為普通視圖暴浦,可通過NotificationCompat.Builder.setStyle()設置大視圖。

注: 大視圖(Big Views)由Android 4.1(API level 16)開始引入晓锻,且僅支持Android 4.1及更高版本歌焦。

構(gòu)建大視圖通知

以上圖為例:
1、構(gòu)建Action Button的PendingIntent

Intent dismissIntent = new Intent(this, PingService.class);
dismissIntent.setAction(CommonConstants.ACTION_DISMISS);
PendingIntent piDismiss = PendingIntent.getService(
      this, 0, dismissIntent, 0);

Intent snoozeIntent = new Intent(this, PingService.class);
snoozeIntent.setAction(CommonConstants.ACTION_SNOOZE);
PendingIntent piSnooze = 
      PendingIntent.getService(this, 0, snoozeIntent, 0);

2砚哆、構(gòu)建NotificatonCompat.Builder對象

NotificationCompat.Builder builder = 
      new NotificationCompat.Builder(this)
          .setSmallIcon(R.drawable.ic_stat_notification)
          .setContentTitle(getString(R.string.notification))
          .setContentText(getString(R.string.ping))
          .setDefaults(Notification.DEFAULT_ALL)
        // 該方法在Android 4.1之前會被忽略
          .setStyle(new NotificationCompat.BigTextStyle()
                .bigText(msg))
        //添加Action Button
        .addAction (R.drawable.ic_stat_dismiss,
                getString(R.string.dismiss), piDismiss)
        .addAction (R.drawable.ic_stat_snooze,
                getString(R.string.snooze), piSnooze);

3独撇、其他步驟與普通視圖相同

進度條通知

  • 明確進度的進度條
    使用setProgress(max, progress, false)來更新進度。
    max: 最大進度值
    progress: 當前進度
    false: 是否是不明確的進度條

    模擬下載過程躁锁,示例如下:

    int id = 1;
    ...
    mNotifyManager = (NotificationManager) 
        getSystemService(Context.NOTIFICATION_SERVICE);
    mBuilder = new NotificationCompat.Builder(this);
    mBuilder.setContentTitle("Picture Download")
        .setContentText("Download in progress")
        .setSmallIcon(R.drawable.ic_notification);
    
    // Start a lengthy operation in a background thread
    new Thread(
        new Runnable() {
            @Override
            public void run() {
                int incr;
                for (incr = 0; incr <= 100; incr+=5) {
                    mBuilder.setProgress(100, incr, false);
                    mNotifyManager.notify(id, mBuilder.build());
                    try {
                        // Sleep for 5 seconds
                        Thread.sleep(5*1000);
                    } catch (InterruptedException e) {
                        Log.d(TAG, "sleep failure");
                    }
                }
                mBuilder.setContentText("Download complete")//下載完成           
                        .setProgress(0,0,false);    //移除進度條
                mNotifyManager.notify(id, mBuilder.build());
            }
        }
    ).start();
    


    上圖纷铣,分別為下載過程中進度條通知 和 下載完成移除進度條后的通知。

  • 不確定進度的進度條
    使用setProgress(0, 0, true)來表示進度不明確的進度條

    mBuilder.setProgress(0, 0, true); mNotifyManager.notify(id, mBuilder.build());

浮動通知(Heads-up Notifications)

Android 5.0(API level 21)開始战转,當屏幕未上鎖且亮屏時关炼,通知可以以小窗口形式顯示。用戶可以在不離開當前應用前提下操作該通知匣吊。
如圖:

NotificationCompat.Builder mNotifyBuilder = 
    new NotificationCompat.Builder(this)
        .setContentTitle("New Message")
        .setContentText("You've received new messages.")
        .setSmallIcon(R.drawable.ic_notify_status)
        .setFullScreenIntent(pendingIntent, false);

以下兩種情況會顯示浮動通知:

  • setFullScreenIntent()儒拂,如上述示例。
  • 通知擁有高優(yōu)先級且使用了鈴聲和振動

鎖屏通知

Android 5.0(API level 21)開始色鸳,通知可以顯示在鎖屏上社痛。用戶可以通過設置選擇是否允許敏感的通知內(nèi)容顯示在安全的鎖屏上。
你的應用可以通過setVisibility()控制通知的顯示等級:

  • VISIBILITY_PRIVATE : 顯示基本信息命雀,如通知的圖標蒜哀,但隱藏通知的全部內(nèi)容
  • VISIBILITY_PUBLIC : 顯示通知的全部內(nèi)容
  • VISIBILITY_SECRET : 不顯示任何內(nèi)容,包括圖標

自定義通知

Android系統(tǒng)允許使用RemoteViews來自定義通知吏砂。
自定義普通視圖通知高度限制為64dp撵儿,大視圖通知高度限制為256dp。同時狐血,建議自定義通知盡量簡單淀歇,以提高兼容性。

自定義通知需要做如下操作:
1匈织、創(chuàng)建自定義通知布局
2浪默、使用RemoteViews定義通知組件,如圖標缀匕、文字等
3纳决、調(diào)用setContent()將RemoteViews對象綁定到NotificationCompat.Builder
4、同正常發(fā)送通知流程

注意: 避免為通知設置背景乡小,因為兼容性原因阔加,有些文字可能看不清。

定義通知文本樣式

通知的背景顏色在不同的設備和版本中有所不同满钟,Android2.3開始胜榔,系統(tǒng)定義了一套標準通知文本樣式约急,建議自定義通知使用標準樣式,這樣有助于通知文本可見苗分。
通知文本樣式:

Android 5.0之前可用:
android:style/TextAppearance.StatusBar.EventContent.Title    // 通知標題樣式  
android:style/TextAppearance.StatusBar.EventContent             // 通知內(nèi)容樣式  

Android 5.0及更高版本:  
android:style/TextAppearance.Material.Notification.Title         // 通知標題樣式  
android:style/TextAppearance.Material.Notification                  // 通知內(nèi)容樣式  

更多通知的標準樣式和布局,可參考源碼frameworks/base/core/res/res/layout路徑下的通知模版如:

Android 5.0之前:  
notification_template_base.xml  
notification_template_big_base.xml  
notification_template_big_picture.xml  
notification_template_big_text.xml  

Android 5.0 及更高版本:  
notification_template_material_base.xml  
notification_template_material_big_base.xml  
notification_template_material_big_picture.xml  
notification_template_part_chronometer.xml  
notification_template_progressbar.xml  

等等牵辣。

保留Activity返回棧

常規(guī)Activity

默認情況下摔癣,從通知啟動一個Activity,按返回鍵會回到主屏幕纬向。但某些時候有按返回鍵仍然留在當前應用的需求择浊,這就要用到TaskStackBuilder了。

1逾条、在manifest中定義Activity的關(guān)系

Android 4.0.3 及更早版本
<activity
    android:name=".ResultActivity">
    <meta-data
        android:name="android.support.PARENT_ACTIVITY"
        android:value=".MainActivity"/>
</activity>

Android 4.1 及更高版本
<activity
    android:name=".ResultActivity"
    android:parentActivityName=".MainActivity">
</activity>

2琢岩、創(chuàng)建返回棧PendingIntent

Intent resultIntent = new Intent(this, ResultActivity.class);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
// 添加返回棧
stackBuilder.addParentStack(ResultActivity.class);
// 添加Intent到棧頂
stackBuilder.addNextIntent(resultIntent);
// 創(chuàng)建包含返回棧的pendingIntent
PendingIntent resultPendingIntent =
        stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);

NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder.setContentIntent(resultPendingIntent);
NotificationManager mNotificationManager =
    (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(id, builder.build());

上述操作后,從通知啟動ResultActivity师脂,按返回鍵會回到MainActivity担孔,而不是主屏幕。

特殊Activity

默認情況下吃警,從通知啟動的Activity會在近期任務列表里出現(xiàn)糕篇。如果不需要在近期任務里顯示,則需要做以下操作:

1酌心、在manifest中定義Activity

<activity
    android:name=".ResultActivity"
    android:launchMode="singleTask"
    android:taskAffinity=""
    android:excludeFromRecents="true">
</activity>

2拌消、構(gòu)建PendingIntent

NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
Intent notifyIntent = new Intent(this, ResultActivity.class);

// Sets the Activity to start in a new, empty task
notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK 
        | Intent.FLAG_ACTIVITY_CLEAR_TASK);

PendingIntent notifyPendingIntent =
        PendingIntent.getActivity(this, 0, notifyIntent, 
        PendingIntent.FLAG_UPDATE_CURRENT);

builder.setContentIntent(notifyPendingIntent);
NotificationManager mNotificationManager =
    (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(id, builder.build());

上述操作后,從通知啟動ResultActivity安券,此Activity不會出現(xiàn)在近期任務列表中墩崩。

通知常見屬性和常量

通知的提醒方式

1、聲音提醒

  • 默認聲音
    notification.defaults |= Notification.DEFAULT_SOUND;
  • 自定義聲音
    notification.sound = Uri.parse("file:///sdcard0/notification.ogg");

2侯勉、震動提醒

  • 默認振動
    notification.defaults |= Notification.DEFAULT_VIBRATE;
  • 自定義振動
    long[] vibrate = {100, 200, 300, 400}; //震動效果
    // 表示在100鹦筹、200、300址貌、400這些時間點交替啟動和關(guān)閉震動 notification.vibrate = vibrate;

3盛龄、閃爍提醒

  • 默認閃爍
    notification.defaults |= Notification.DEFAULT_LIGHTS;
  • 自定義閃爍
    notification.ledARGB = 0xff00ff00; // LED燈的顏色,綠燈
    notification.ledOnMS = 300; // LED燈顯示的毫秒數(shù)芳誓,300毫秒
    notification.ledOffMS = 1000; // LED燈關(guān)閉的毫秒數(shù)余舶,1000毫秒
    notification.flags |= Notification.FLAG_SHOW_LIGHTS; // 必須加上這個標志

常見的Flags

  • FLAG_AUTO_CANCEL
    當通知被用戶點擊之后會自動被清除(cancel)
  • FLAG_INSISTENT
    在用戶響應之前會一直重復提醒音
  • FLAG_ONGOING_EVENT
    表示正在運行的事件
  • FLAG_NO_CLEAR
    通知欄點擊“清除”按鈕時,該通知將不會被清除
  • FLAG_FOREGROUND_SERVICE
    表示當前服務是前臺服務
    更多Notification屬性詳見Notification锹淌。

That's all匿值! 更多通知知識點等待你來發(fā)掘,歡迎補充!

參考資料
Notifications

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末赂摆,一起剝皮案震驚了整個濱河市挟憔,隨后出現(xiàn)的幾起案子钟些,更是在濱河造成了極大的恐慌,老刑警劉巖绊谭,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件政恍,死亡現(xiàn)場離奇詭異,居然都是意外死亡达传,警方通過查閱死者的電腦和手機篙耗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來宪赶,“玉大人宗弯,你說我怎么就攤上這事÷蓿” “怎么了蒙保?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長欲主。 經(jīng)常有香客問我邓厕,道長,這世上最難降的妖魔是什么扁瓢? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任邑狸,我火速辦了婚禮,結(jié)果婚禮上涤妒,老公的妹妹穿的比我還像新娘单雾。我一直安慰自己,他們只是感情好她紫,可當我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布硅堆。 她就那樣靜靜地躺著,像睡著了一般贿讹。 火紅的嫁衣襯著肌膚如雪渐逃。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天民褂,我揣著相機與錄音茄菊,去河邊找鬼。 笑死赊堪,一個胖子當著我的面吹牛面殖,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播哭廉,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼脊僚,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了遵绰?” 一聲冷哼從身側(cè)響起辽幌,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤增淹,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后乌企,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體虑润,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年加酵,在試婚紗的時候發(fā)現(xiàn)自己被綠了拳喻。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡虽画,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出荣病,到底是詐尸還是另有隱情码撰,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布个盆,位于F島的核電站脖岛,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏颊亮。R本人自食惡果不足惜柴梆,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望终惑。 院中可真熱鬧绍在,春花似錦、人聲如沸雹有。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽霸奕。三九已至溜宽,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間质帅,已是汗流浹背适揉。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留煤惩,地道東北人嫉嘀。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像魄揉,于是被迫代替她去往敵國和親吃沪。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,792評論 2 345

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

  • 原文出處: http://www.androidchina.net/6174.html Notification在...
    木木00閱讀 12,290評論 3 32
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,506評論 25 707
  • 內(nèi)容抽屜菜單ListViewWebViewSwitchButton按鈕點贊按鈕進度條TabLayout圖標下拉刷新...
    皇小弟閱讀 46,708評論 22 664
  • 一什猖、什么是Notification? Notification是一種有全局效果的通知票彪,可以顯示在系統(tǒng)通知欄红淡。以下內(nèi)...
    douhao1333閱讀 726評論 0 1
  • 甘德禮(別樣的中秋晚會)持續(xù)原創(chuàng)分享第84天 今天是信陽焦點團隊一個特別的夜晚,一個極具創(chuàng)意的夜晚降铸,把焦點知識學習...
    華南帝虎閱讀 461評論 2 5