分类: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的用法就不说了。
下一节咱们再用完整例子说明具体用法。