Android文本时钟 — Part4

643 查看

前一篇文章中,我们已经可以在文本时钟小部件上显示时间,但是这个时间无法自动更新。在本文中我们将会使用AlarmManager定时更新小部件。

之前,我们讨论过IntentService以及如何使用它去执行ActionAlarmManager为我们提供了一个定时启动IntentService的完美机制。希望本文能帮你了解如何使用Intent启动Android Service(之前介绍并使用过)。如何设定AlarmManager在某段时间间隔后执行这个Action,并且可以选择时间间隔重复执行。不止局限于启动服务(Service),AlarmManager还可以执行许多其它Action。它可以发送广播并启动活动(Activity)。PendingIntent用来表示将要被执行的Action,由AlarmManager安排这个Action将要执行的时间。

让我们考虑一下我们的应用小部件应当如何更新。当用户在主页面创建一个小部件时会调用TextClockAppWidgetonUpdate()方法。到目前为止,我们只是在这个函数里更新小部件的时间,没有做任何其他事情。但其实我们还可以在这个方法里安排即将要进行的更新。当然,我们仍然希望在这里更新初始时间,所以我们保持startService()不变。我们希望做的是生成一个Alarm,这个Alarm会每分钟触发一个PendingIntent,调用一次startService()(当时间从59秒变到00秒的时候,分钟数加一)确保小部件显示精确的时间。

有一点要注意,用户可能安装多个小部件实例。但是我们只需要一个Alarm更新。我们的时钟小部件本来就应该在同一时间更新,因此启动多个服务就有些浪费了。坏消息是,AlarmManager不允许我们查询设置了哪些Alarm,这让事情变得有些复杂。好消息是,我们可以通过PendingIntent检测是否有一个已经设置的Alarm。即使是创建在不同的线程、进程、甚至应用程序中,如果PendingIntent使用相同的操作(Operation)、Intent Action、数据、分类、组件和标记(Flag),那它就是唯一的PendingIntent。我们可以使用它管理Alarm。

为了便于说明,我们重点关注用PendingIntent来启动服务。同样的技术也可以应用在其他场合。我们无法直接创建PendingIntent,但是PendingIntent类为我们提供了一些静态工厂方法。PendingIntent.getService()能够接受四个参数:

  • Context contextPendingIntent启动的服务上下文。
  • int requestCode:忽略。
  • Intent intent:用作startService()的参数,此函数会在刚才提供的context上调用。
  • int flags:用来控制是否需要以及如何创建或更新PendingIntent

如果我们使用FLAG_NO_CREATE标记,那么PendingIntent.getService()会检查是否有一个带有同样参数的PendingIntent已经存在于此设备上。如果存在返回它的实例,否则返回null。因此我们可以使用这个方法确保只存在一个PendingIntent

如果创建PendingIntent时只创建了一个Alarm,那就可以保证只有一个Alarm

我们还可以应用于TextClockAppWidget

我们使用Calendar对象去寻找分钟边界。在每一个分钟边界处,我们设置一个每分钟重复的Alarm。我们需要指定Alarm类型为RTC而不是RTC_WAKEUP,以此达到省电的目的。即使你的手机处于休眠状态RTC_WAKEUP也会启动服务,然而在用户没有看手机的情况下唤醒设备并更新时间太费电。而使用RTC时,服务会在下一次设备醒来时启动(因此总是显示准确时间),但不会唤醒设备。

作为拥有良好习惯的Android程序员,需要在用户移除我们的应用小部件实例时删除Alarm

onDelete()在用户每次移除小部件实例时触发,所以我们需要检查是否还有其他实例。如果已经没有任何实例,那就移除Alarm。我们必须在这里移除PendingIntent,如果不这样做即使已经没有与它关联的Alarm,小部件还会一直在系统中处于活跃(Active)状态。这样会导致我们在scheduleTimer()中检查PendingIntent失效。

如果我们运行程序,将会看到这个版本的文本时钟显示的是精确时间!

textclock_4_widget_update

现在我们有了一个实现基本功能的App:可以精确显示时间。这就是Google Play上这个App的1.0.0版本。

我们将在下一章中继续学习如何改进。

本文的源代码可以在这里找到,文本使用可以从Google Play下载。