Notification的基本用法以及使用RemoteView實現自定義布局
Notification的作用
Notification是一種全局效果的通知,在系統的通知欄中顯示。既然作為通知,其基本作用有:
- 顯示接收到短消息、即時信息等
- 顯示客戶端的推送(廣告、優惠、新聞等)
- 顯示正在進行的事物(後臺運行的程序,如音樂播放進度、下載進度)
Notification的基本操作:
Notification的基本操作主要有創建、更新和取消三種。一個Notification的必要屬性有三項,如果不設置的話在運行時會拋出異常:
- 小圖標,通過setSmallIcon方法設置
- 標題,通過setContentTitle方法設置
- 內容,通過setContentText方法設置。
除了以上三項,其他均為可選項,不過一般而言,通知需要有交互的功能,所以一般Notification具有Action屬性,這樣就能跳轉到App的某一個Activity、啟動一個service或者發送一個Broadcast。
當系統受到通知時,可以通過震動、鈴聲、呼吸燈等多種方式進行提醒。
下面就從Notification的基本操作逐條介紹:
- Notification的創建
Notification的創建過程主要涉及到Notification.Builder、Notification、NotificationManager
Notification.Builder:
使用建造者模式構建Notification對象。由於Notification.Builder僅支持Android4.1及之後的版本,為了解決兼容性的問題,使用V4兼容庫中的NotifivationCompat.Builder類。
Notification:通知對應類,保存通知相關的數據。NotificationManager向系統發送通知時會用到。
NotificationManager:通知管理類,調用NotificationManager的notify方法可以向系統發送通知。
獲取 NotificationManager 對象:
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
前面講到,Notification有三個必要屬性以及一個很有必要的屬性Action。下面我們就創建一個簡單的Notification,主要有以下三步:
- 獲取NotificationManager實例
- 實例化NotificationCompat.Builder並設置相關屬性
- 通過builder.build方法來生成Notification對象,並發送通知
private void sendNotification(){ Intent intent = new Intent(this,SettingsActivity.class); PendingIntent mPendingIntent = PendingIntent.getActivity(this,0,intent,PendingIntent.FLAG_ONE_SHOT); NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); NotificationCompat.Builder builder = (NotificationCompat.Builder) new NotificationCompat.Builder(this) //設置小圖標 .setSmallIcon(R.mipmap.ic_launcher) //點擊後自動清除 .setAutoCancel(true) //設置通知標題 .setContentTitle("最簡單的通知") //設置通知內容 .setContentText("真的很簡單很簡單很簡單") //設置通知的動作 .setContentIntent(mPendingIntent) //設置通知時間,默認為系統發出通知的時間 .setWhen(System.currentTimeMillis()); //第一個參數為Notification的id notificationManager.notify(2,builder.build()); }
其中為了實現Action屬性,我們需要創建Intent、PendingIntent和setContentIntent()這幾步。
不難發現,其中的PendingIntent的設置才是其中的關鍵。
PendingIntent支持三種待定的意圖:啟動Activity,啟動Service和發送Broadcast。對應於它的三個接口方法。
static PendingIntent |
getActivity(Context context,int requestCode,Intent intent,int flags) 獲取一個PendingIntent,該意圖發生時,相當於Context.startActivity(Intent) |
static PendingIntent |
getService (Context context,int requestCode,Intent intent,int flags) 獲取一個PendingIntent,該意圖發生時,相當於Context.startService (Intent) |
static PendingIntent |
getBroadcast(Context context,int requestCode,Intent intent,int flags) 獲取一個PendingIntent,該意圖發生時,相當於Context.sendBroadcast(Intent) |
其中context和intent不需要講,主要說一下requestCode和flags。其中requestCode是PendingIntent發送發的請求碼,多數情況下設置為0即可,requestCode會影響到flags的效果。
PendingIntent相同:Intent相同且requestCode也相同。(Intent相同需要ComponentName和intent-filter相同)
flags的常見類型有:
FLAG_ONE_SHOT:只能被使用一次,然後就會被自動cancel,如果後續還有相同的PendingIntent。那麽他們的send方法就會調用失敗。
FLAG_NO_CREATE:如果當前系統中不存在相同的PendingIntent對象,系統不會創建該PendingIntent對象,而是直接返回null。(很少使用)
FLAG_CANCEL_CURRENT:如果當前系統中已經存在一個相同的 PendingIntent 對象,那麽就將先將已有的 PendingIntent 取消,然後重新生成一個 PendingIntent 對象。
FLAG_UPDATE_CURRENT:當前描述的PendingIntent如果已經存在,那麽它們會被更新,即Intent中的Extras會被替換到最新的。
- Notification的更新
更新通知的操作很簡單,只需要再次發送一次相同ID的通知即可,如果之前的通知還沒有被取消,則會直接更新該通知相關的屬性;如果之前的通知已經被取消,則會重新創建一個新的通知。
更新通知和發送通知采用同樣的方法。
- Notification的取消
取消通知的方式主要有以下5種:
- 點擊通知欄的清除按鈕,會清除所有可清除的通知
- 設置了setAutoCancel()或者設置了flags為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) 或cancelAll()方法才能清除對應的通知,調用NotificationManager.cancel(int id) 無效。
- Notification的通知效果
前面提到了Notification的通知效果,有了通知效果更能提醒用戶去查看Notification。
Notification的通知效果有震動、呼吸燈、鈴聲三種,可以通過builder中的setDefaults(int defaults)方法來設置,屬性有以下四種,一旦設置了默認效果,自定義效果就會失效。
//添加默認震動效果,需要申請震動權限 //<uses-permission android:name="android.permission.VIBRATE" /> Notification.DEFAULT_VIBRATE //添加系統默認聲音效果,設置此值後,調用setSound()設置自定義聲音無效 Notification.DEFAULT_SOUND //添加默認呼吸燈效果,使用時須與 Notification.FLAG_SHOW_LIGHTS 結合使用,否則無效 Notification.DEFAULT_LIGHTS //添加上述三種默認提醒效果 Notification.DEFAULT_ALL
鈴聲:
//調用系統默認響鈴,設置此屬性後setSound()會無效 //.setDefaults(Notification.DEFAULT_SOUND) //調用系統多媒體褲內的鈴聲 //.setSound(Uri.withAppendedPath(MediaStore.Audio.Media.INTERNAL_CONTENT_URI,"2")); //調用自己提供的鈴聲,位於 /res/values/raw 目錄下 .setSound(Uri.parse("android.resource://com.littlejie.notification/" + R.raw.sound))
震動:
long[] vibrate = new long[]{0, 500, 1000, 1500}; //使用系統默認的震動參數,會與自定義的沖突 //.setDefaults(Notification.DEFAULT_VIBRATE) //自定義震動效果 .setVibrate(vibrate);
呼吸燈
//ledARGB 表示燈光顏色、 ledOnMS 亮持續時間、ledOffMS 暗的時間 .setLights(0xFF0000, 3000, 3000);
另一種方式:
Notification notification = builder.build(); //只有在設置了標誌符Flags為Notification.FLAG_SHOW_LIGHTS的時候,才支持呼吸燈提醒。 notify.flags = Notification.FLAG_SHOW_LIGHTS; //設置lights參數的另一種方式 //notify.ledARGB = 0xFF0000; //notify.ledOnMS = 500; //notify.ledOffMS = 5000;
還可以通過以下幾種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
上面講到的Notification的布局都是系統默認的,當然有時候處於需求,我們可能需要自定義Notification的布局。
那如何實現Notification的自定義布局呢?
這裏就需要提出一個新的知識點RemoteView,望文生義,即遠程View。
RemoteView表示的是一種View結構,它可以在其他進程中顯示(具體來講是SystemServer進程),由於它是在其他進程中顯示,為了更新它的界面,我們不能簡單地使用普通View的那一套方法,RemoteView提供了一系列Set方法用於更新界面。
下面就是一個簡單的示例;
package com.pignet.remoteviewtest; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.RemoteViews; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button btnNotification = (Button) findViewById(R.id.btn_notification); btnNotification.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { sendNotification(); } }); } private void sendNotification(){ NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); Notification notification =new Notification(); notification.icon=R.mipmap.ic_launcher; notification.when=System.currentTimeMillis(); notification.flags=Notification.FLAG_AUTO_CANCEL; //跳轉意圖 Intent intent = new Intent(this,SettingsActivity.class); //建立一個RemoteView的布局,並通過RemoteView加載這個布局 RemoteViews remoteViews = new RemoteViews(getPackageName(),R.layout.layout_notification); //為remoteView設置圖片和文本 remoteViews.setTextViewText(R.id.message,"第一條通知"); remoteViews.setImageViewResource(R.id.image,R.mipmap.ic_launcher_round); //設置PendingIntent PendingIntent pendingIntent = PendingIntent.getActivity(this,0,intent,PendingIntent.FLAG_UPDATE_CURRENT); //為id為openActivity的view設置單擊事件 remoteViews.setOnClickPendingIntent(R.id.openActivity,pendingIntent); //將RemoteView作為Notification的布局 notification.contentView =remoteViews; //將pendingIntent作為Notification的intent,這樣當點擊其他部分時,也能實現跳轉 notification.contentIntent=pendingIntent; notificationManager.notify(1,notification); } }
有圖:
Notification的基本用法以及使用RemoteView實現自定義布局