分類:C#、Android、VS2015; 安全
建立日期:2016-02-29 網絡
一、使用Toast通知用戶 app
前臺任務中的通知(Notifications)通常用於長時間顯示用戶正在關注的服務的消息。但有時候,咱們可能只但願將最終結果短暫地顯示出來,好比告訴用戶文件已下載完畢等,此時能夠用Toast告訴用戶。 ide
因爲服務是在後臺運行的,因此能夠在服務中用Handler來實現Toast的顯示。例如: 佈局
var myHandler = new Handler (); post
... 測試
myHandler.Post(() => ui
{ this
Toast.MakeText (this, "Message from demo service", ToastLength.Long).Show(); spa
});
除了用Handler實現之外,也能夠在服務中用其餘的辦法來實現,例如:
Android.App.Application.SynchronizationContext.Post(()=>
{
Toast.MakeText (this, "Message from demo service", ToastLength.Long).Show();
});
或者:
System.Threading.SynchronizationContext.Current.Post(()=>
{
Toast.MakeText (this, "Message from demo service", ToastLength.Long).Show();
});
二、使用Notification通知用戶
從前面的介紹中咱們已經明白,安卓的服務組件(Android Service,後面章節再細講)原本是在後臺運行的,但是,用戶可能但願關注它正在執行的狀態或者當前的結果,換言之,這個服務的狀態監控很是重要。此時就能夠將「監控」做爲前臺任務來處理,即:用「通知」的辦法及時告訴用戶後臺服務當前正在運行的狀況。
下面的示例演示瞭如何在前臺實現通知:
public class MyService : Service { …… public override StartCommandResult OnStartCommand(……) { var pendingIntent = PendingIntent.GetActivity(this, 0, new Intent(this, typeof(MainActivity)), PendingIntentFlags.UpdateCurrent); Notification.Builder builder = new Notification.Builder(this) .SetContentTitle("來自MyService的通知") .SetContentText("正在前臺運行MyService") .SetContentIntent(pendingIntent) .SetSmallIcon(Resource.Drawable.Icon); Notification notification = builder.Build(); //啓動前臺任務 StartForeground((int)NotificationFlags.ForegroundService, notification); var t = new Thread(() => { //發送通知 var m = (NotificationManager)GetSystemService(NotificationService); m.Notify(0, notification); //….在此處執行後臺運行的任務 …… //中止前臺任務 StopForeground(true); …… }); t.Start(); return StartCommandResult.NotSticky; } }
在上面的代碼中,先經過Notification對象建立一個通知,而後將此通知傳遞給StartForeground()方法以及NotificationFlags.ForegroundService標誌,這樣一來,就能夠提醒用戶這個前臺通知的是正在運行的服務的執行狀況。
要移除某個前臺任務,只需調用StopForeground()方法便可。能夠給該方法傳遞一個布爾值,指示是否同時移除通知。經過StopForeground()方法中止前臺任務的目的是爲了減小系統的內存壓力,但實際上並無中止後臺服務。
當後臺服務真正中止時,若是通知仍在繼續,該通知也將同時被移除。
Android從5.0開始提供了兩個由系統控制的佈局區域來顯示通知。
當首次發佈一個通知時,它會在屏幕左上角顯示一個通知圖標,以下面左側的圖所示(左上角有三個通知)。當用戶下拉或點擊通知圖標時,它就會把每一個通知的詳細信息顯示出來,以下面右側的圖所示:
Android提供了兩個由系統控制的佈局區域來顯示通知:
一、基本佈局(Base Layout)
在緊湊格式的基本佈局中,一個通知由四部分組成:圖標、標題、信息、時間戳:
默認狀況下,基本佈局區域的高度被限制爲64dp。
做爲可選項,也能夠用大圖標或圖片代替標準圖標。在Android 5.0 及更高版本中,原來的標準圖標將會貼在圖片的右下角,以下圖所示:
從Android 5.0開始,當出現通知時會自動鎖屏(以下圖所示),用戶能夠雙擊通知來解鎖設備切換通知的顯示和隱藏。在應用程序中,能夠設置鎖屏界面的可見級別來控制何時顯示通知,用戶也能夠選擇鎖屏時是否容許在通知中顯示敏感內容。
除此以外,Android從5.0開始還引入了一個稱爲上吊式(Heads-up)的高優先級通知格式,這種格式的通知會先從屏幕頂部向下滑落幾秒鐘,而後再自動退回到原來的通知區域。
Heads-up--「頭條懸掛」樣式的通知,感受還不如叫「上吊式」形象呢,反正就是看着好像用橡皮筋吊我的頭或者長方體開始時一高一低上下襬動幾下的意思,呵呵。
Heads-up主要用於顯示一些重要的通知信息。
安卓系統還支持讓通知包含元數據,以便對其進行更智能化的排序和顯示。利用通知提供的元數據,能夠控制如何呈現通知的格式。應用程序能夠設置如下類型的元數據:
注意:Visibility和Category都是從Android 5.0開始引入的,沒法在低版本的系統中使用。
二、擴展布局(Expanded Layouts)
Expanded Layouts是從Android 4.1開始提供的。這種方式容許展開佈局的高度,以即可觀察更多的內容。例如,下面的圖演示了可展開佈局默認的通知形式:
當展開該通知時,就會顯示所有內容:
Android爲單事件的通知提供了3種展開方式:
本節後面還會解釋如何建立大文本、收件箱和圖像的通知。
Notification.Builder是從Android 3.0開始引入的類,專門用於建立通知。若是但願應用程序兼容舊版本(<3.0),能夠改成用NotificationCompat.Builder類來實現。
Notification.Builder提供了設置通知類型的各類選項和方法。例如:
Android提供了一個NotificationManager類負責發佈通知。在builder中設置了這些上面的選項後,就能夠生成包含設置的通知對象。若要發佈通知,將通知對象傳遞給通知委託,並將它們顯示給用戶便可。
能夠在任何上下文中獲取對此類的引用,如某項活動或一項服務。
一、生成通知
下面的步驟說明了如何生成一個通知:
每一個通知至少要提供下面的信息:
下面的代碼演示瞭如何用Notification.Builder生成通知:
// 實例化builder並設置通知元素: Notification.Builder builder = new Notification.Builder (this) .SetContentTitle ("簡單通知示例") .SetContentText ("你好,這是第一個通知!") .SetSmallIcon (Resource.Drawable.ic_notification); // 建立通知: Notification notification = builder.Build(); // 獲取通知管理器: NotificationManager notificationManager = GetSystemService (Context.NotificationService) as NotificationManager; // 發佈通知: const int notificationId = 0; notificationManager.Notify (notificationId, notification);
Notify方法包含2個參數:第1個是int類型的通知標識,第2個是通知的實例。通常狀況下,通知標識應該是不重複的,若是重複,那麼它將覆蓋具備同名標識的通知。
這段代碼在Android 5.0及更高版本上的運行效果以下:
時間戳(timestamp)默認是自動設置的,你也能夠調用notification builder的SetWhen方法重寫該設置。例如:
builder.SetWhen (Java.Lang.JavaSystem.CurrentTimeMillis());
二、容許聲音(Sound)和振動(Vibration)
若是但願顯示通知時播放聲音,可調用builder的SetDefaults方法並傳遞NotificationDefaults.Sound標誌:
Notification.Builder builder = new Notification.Builder (this) .SetContentTitle ("Sample Notification") .SetContentText ("Hello World! This is my first notification!") .SetDefaults (NotificationDefaults.Sound) .SetSmallIcon (Resource.Drawable.ic_notification);
NotificationDefaults.Vibrate用於讓設備振動而不是播放聲音。若是但願在播放聲音時同時也讓設備振動,可用下面的辦法實現:
builder.SetDefaults (NotificationDefaults.Sound | NotificationDefaults.Vibrate);
默認狀況下,Android將用系統默認的通知音。固然也能夠指定播放的通知音,例如:
builder.SetSound (RingtoneManager.GetDefaultUri(RingtoneType.Alarm));
或者用默認的通知音播放:
builder.SetSound (RingtoneManager.GetDefaultUri(RingtoneType.Ringtone));
當建立一個通知實例後,也能夠直接設置該對象的屬性來設置播放音,而不是調用Notification.Builder的SetDefaults方法來實現。例如:
Notification notification = builder.Build();
notification.Defaults |= NotificationDefaults.Vibrate;
設備振動效果只能在真機上測試,在模擬器上看不出來。
三、更新通知
下面的代碼演示瞭如何更新已發佈的通知:
// Update the existing notification builder content: builder.SetContentTitle ("Updated Notification"); builder.SetContentText ("Changed to this message."); // Build a notification object with updated content: notification = builder.Build(); // Publish the new notification with the existing ID: notificationManager.Notify (notificationId, notification);
這段代碼使用已存在的Notification.Builder對象建立一個新的通知,可是其標識號和原來已存在的通知的標識號相同,此時它會覆蓋原來的通知,其效果就是更新了通知。更新後的運行效果以下圖:
除非發生了下面的狀況之一,不然通知將會一直顯示:
四、從通知中啓動一個Activity
在Android中,常見的狀況是將通知與某個活動相關聯(用戶點擊通知時自動運行該活動),該活動能夠駐留在另外一個應用程序中或另外一項任務中。
要將某個操做(action)添加到通知,可建立PendingIntent對象並將其與通知相關聯。PendingIntent是一種特殊的Intent,它容許接收通知的應用程序使用發送應用程序的權限來運行預約義的片斷。當用戶點擊通知時,Android就會啓動PendingIntent中指定的Activity。
下面的代碼演示瞭如何將PendingIntent與MainActivity相關聯:
// Set up an intent so that tapping the notifications returns to this app: Intent intent = new Intent (this, typeof(MainActivity)); // Create a PendingIntent; we're only using one PendingIntent (ID = 0): const int pendingIntentId = 0; PendingIntent pendingIntent = PendingIntent.GetActivity (this, pendingIntentId, intent, PendingIntentFlags.OneShot); // Instantiate the builder and set notification elements, including pending intent: Notification.Builder builder = new Notification.Builder(this) .SetContentIntent (pendingIntent) .SetContentTitle ("Sample Notification") .SetContentText ("Hello World! This is my first action notification!") .SetSmallIcon (Resource.Drawable.ic_notification); // Build the notification: Notification notification = builder.Build(); // Get the notification manager: NotificationManager notificationManager = GetSystemService (Context.NotificationService) as NotificationManager; // Publish the notification: const int notificationId = 0; notificationManager.Notify (notificationId, notification);
在這段代碼中,將PendingIntentFlags.OneShot標誌傳遞給PendingIntent.GetActivity方法,意思是僅使用一次PendingIntent。
運行這段代碼將顯示下面的通知:
點擊通知則回退到原來的活動。
在實際的應用程序中,必須處理用戶單擊BACK按鈕的狀況,大多數狀況下,退出通知活動將會返回到系統主頁(Home Screen)而不是回退到原來的活動。避免回不到原來的活動的處理辦法就是經過TaskStackBuilder類爲back堆棧建立一個PendingIntent。
另外一種實際狀況就是可能須要從原來的活動中向通知的活動發送數據。例如,通知可能指出下一個消息已到達,此時顯示通知的活動(即屏幕的消息窗口)會獲取下一個消息的ID號以便顯示它,此時,建立PendingIntent的Activity能夠經過PutExtra方法添加Intent須要的數據(好比添加一個字符串)做爲要顯示的下一個消息傳遞給原來的活動。
下面的代碼演示瞭如何使用TaskStackBuilder控制back stack,也演示瞭如何發送一個字符串到通知到SecondActivity:
// Setup an intent for SecondActivity: Intent secondIntent = new Intent (this, typeof(SecondActivity)); // Pass some information to SecondActivity: secondIntent.PutExtra ("message", "Greetings from MainActivity!"); // Create a task stack builder to manage the back stack: TaskStackBuilder stackBuilder = TaskStackBuilder.Create(this); // Add all parents of SecondActivity to the stack: stackBuilder.AddParentStack (Java.Lang.Class.FromType (typeof (SecondActivity))); // Push the intent that starts SecondActivity onto the stack: stackBuilder.AddNextIntent (secondIntent); // Obtain the PendingIntent for launching the task constructed by // stackbuilder. The pending intent can be used only once (one shot): const int pendingIntentId = 0; PendingIntent pendingIntent = stackBuilder.GetPendingIntent (pendingIntentId, PendingIntentFlags.OneShot); // Instantiate the builder and set notification elements, including // the pending intent: Notification.Builder builder = new Notification.Builder (this) .SetContentIntent (pendingIntent) .SetContentTitle ("Sample Notification") .SetContentText ("Hello World! This is my second action notification!") .SetSmallIcon (Resource.Drawable.ic_notification); // Build the notification: Notification notification = builder.Build(); // Get the notification manager: NotificationManager notificationManager = GetSystemService (Context.NotificationService) as NotificationManager; // Publish the notification: const int notificationId = 0; notificationManager.Notify (notificationId, notification);
在這段代碼中,應用程序包含了兩個活動:MainActivity(包含上面的通知代碼),SecondActivity(用戶點擊通知後看到的活動)。下面是在SecondActivity屏幕上看到的效果:
SecondActivity經過下面的代碼獲取Intent的PutExtra方法傳遞的消息:
// Get the message from the intent:
string message = Intent.Extras.GetString ("message", "");
能夠看出,它獲取到的消息是「Greetings from MainActivity!」。當用戶在SecondActivity屏幕上按下Back按鈕,導航就會退出該應用程序並回到原來的應用程序。
安卓系統默認的通知爲基本佈局格式,你也能夠調用Notification.Builder方法來加強這種基本的格式。本節演示如何將一個大圖片圖標添加到通知中,以及如何建立擴大的佈局通知的示例。
一、大圖標樣式
調用builder的SetLargeIcon方法便可顯示大圖片圖標:
builder.SetLargeIcon (BitmapFactory.DecodeResource (Resources, Resource.Drawable.monkey_icon));
下圖演示了將小圖標改成大圖片圖標後顯示的效果:
注意單擊大圖片圖標時纔會在圖片的右下角顯示小圖標。
該圖片圖標的文件名是Resources/drawable/monkey_icon.png,通常不要將圖片圖標作的過大,不然顯示的通知會很是難看。
二、大文本樣式
對於比較長的通知,能夠用擴展布局模板的辦法來實現(添加BigTextStyle),例如:
// Instantiate the Big Text style: Notification.BigTextStyle textStyle = new Notification.BigTextStyle(); // Fill it with text: string longTextMessage = "I went up one pair of stairs."; longTextMessage += " / Just like me. "; //... textStyle.BigText (longTextMessage); // Set the summary text: textStyle.SetSummaryText ("The summary text goes here."); // Plug this style into the builder: builder.SetStyle (textStyle); // Create the notification and publish it ...
下圖是這段代碼的顯示效果:
大文本(Big Text )通知的最大高度是256 dp。
三、圖片樣式
圖片樣式(Image style)也叫大圖片樣式,利用它可直接在通知中顯示一個大圖像。注意:圖像的最大高度是256 dp,在內存受限的狀況下,Android會自動將其縮放到最大高度。
下面的代碼演示瞭如何用BigPictureStyle設置圖片樣式的通知(Resources/drawable/x_bldg.png文件):
// Instantiate the Image (Big Picture) style: Notification.BigPictureStyle picStyle = new Notification.BigPictureStyle(); // Convert the image to a bitmap before passing it into the style: picStyle.BigPicture (BitmapFactory.DecodeResource (Resources, Resource.Drawable.x_bldg)); // Set the summary text that will appear with the image: picStyle.SetSummaryText ("The summary text goes here."); // Plug this style into the builder: builder.SetStyle (picStyle); // Create the notification and publish it ...
下圖是顯示的效果:
注意:以緊湊格式(compact format)顯示圖片通知時調用的是build的SetContentText方法,此時當通知擴展到圖像時,僅在圖像的上方顯示文本摘要。
也能夠在通知中顯示單獨的圖像文件,而不是將全部圖像所有做爲資源打包到.apk文件中。下面的代碼演示瞭如何將SD卡中的圖像文件做爲通知顯示出來:
// Using the Image (Big Picture) style: Notification.BigPictureStyle picStyle = new Notification.BigPictureStyle(); // Read an image from the SD card, subsample to half size: BitmapFactory.Options options = new BitmapFactory.Options(); options.InSampleSize = 2; string imagePath = "/sdcard/Pictures/my-tshirt.jpg"; picStyle.BigPicture (BitmapFactory.DecodeFile (imagePath, options)); // Set the summary text that will appear with the image: picStyle.SetSummaryText ("Check out my new T-Shirt!"); // Plug this style into the builder: builder.SetStyle (picStyle); // Create notification and publish it ...
這段代碼加載SD卡上的圖像文件(/sdcard/Pictures/my-tshirt.jpg),將其縮放到原始大小的一半後做爲通知顯示出來。效果以下:
在高級應用中,若是你不知道圖像文件的大小,當出現內存溢出異常時,可在捕獲的異常中調用BitmapFactory.DecodeFile方法解碼該文件。
關於加載大圖像的並對其進行解碼的詳細信息,可參考「Load Large Bitmaps Efficiently」一文的介紹。
四、收件箱樣式(Inbox Style)
這種格式將通知文本擴展爲中間有一條分割線的兩部分分別顯示(例如上面的部分以緊縮格式顯示收件箱中的郵件摘要,下面的部分顯示剩餘的郵件條數):
下面的代碼演示了這種樣式的具體實現辦法:
// Instantiate the Inbox style: Notification.InboxStyle inboxStyle = new Notification.InboxStyle(); // Set the title and text of the notification: builder.SetContentTitle ("5 new messages"); builder.SetContentText ("chimchim@xamarin.com"); // Generate a message summary for the body of the notification: inboxStyle.AddLine ("Cheeta: Bananas on sale"); inboxStyle.AddLine ("George: Curious about your blog post"); inboxStyle.AddLine ("Nikko: Need a ride to Evolve?"); inboxStyle.SetSummaryText ("+2 more"); // Plug this style into the builder: builder.SetStyle (inboxStyle);
調用InboxStyle的Addline方法可添加分割線上面顯示的主題(body)部分的內容,可是,通知的最大高度仍然被限制爲256dp。
固然,Inbox Style不必定顯示的都是郵件中收件箱的內容,只要是可分割爲兩部分分別顯示的文本內容均可以採用這種樣式。好比把多個通知合併在一塊兒用這種樣式顯示出來,就能夠用這種樣式來實現。
Notification.Builder包含了一些設置元數據的方法,例如優先級(priority)、可見性(visibility)、分類(category)等。安卓系統將在「用戶偏好設置」中使用此信息,以肯定如何以及什麼時候顯示通知。
一、Priority
發佈某個通知時,肯定其優先級設置的兩種原則是:
下面的代碼演示瞭如何設置通知的優先級:
builder.SetPriority (NotificationPriority.High);
注意:在Android 6.0中,若是使用「Head-up」樣式顯示高優先級的通知,必須容許這種通知帶聲音。
Xamarin.Android爲通知的優先級定義了下面的枚舉類型的可選項:
二、Visibility
從Android 5.0開始,這種設置用於控制在鎖屏模式下將有多少條通知內容顯示出來。Xamarin.Android定義了下面的枚舉類型的可選項:
下面的代碼演示瞭如何設置Visibility:
builder.SetVisibility (NotificationVisibility.Private);
三、Category
從Android 5.0開始,可經過預約義的類別排序和篩選通知。Xamarin.Android提供瞭如下枚舉類型的可選項:
當對通知排序時,通知的priority設置優先於category設置。例如,高優先級的通知會用「Heads-up」的方式顯示,即便它屬於促銷類別也是如此。
下面的代碼演示瞭如何設置通知的category屬性:
builder.SetCategory (Notification.CategoryCall);
下圖演示瞭如何用基於類別的通知篩選和過濾「請勿打擾」功能(Android 5.0開始提供)的設置:讓該功能篩選來電顯示通知(即:將「請勿打擾」設置爲Enable,不會影響來電通知的顯示,但會過濾掉Message通知):
注意:「請勿打擾」模式不影響警告通知的顯示,即:Notification.CategoryAlarm通知永遠不會被過濾掉。
若是你設計的App在低於API Level 4的系統上運行,爲了兼容這些舊版本,此時不能用Notification.Builder.,只能用NotificationCompat.Builder類來實現。
因爲如今不多用這麼低的版本,因此NotificationCompat.Builder的用法就不說了。
下一節咱們再用完整例子說明具體用法。