Contents
调度重复闹铃
闹钟(基于AlarmManager类)可以让应用不管自己的生命周期的情况下触发特定时间下的操作。例如,可以用闹钟实现一个长时间的操作,例如启动一个服务,每天下载以下天气预报。
闹钟有以下特点:
- 能够实现在特定的时间和间隔发送intent
- 能够和BroadcastReceiver一起工作,启动Service或者其他操作。
- 他在应用生命周期之外,所以即使应用没启动,也可以工作,甚至即使手机进入睡眠状态也能触发。
- 他可以降低资源消耗,使你不再需要依赖计时器或者持续运行的服务。
注意:对于一定在应用生命周期之内的时间操作,考虑使用Handler, Timer和Thread。这种方法可以使Android更好的控制系统资源。
理解折中
重复的闹铃是一个灵活性方面有所限制的简单机制。他可能是应用的最好选择,尤其是需要出发网络操作的时候。设计的不好的闹铃可能导致耗电和服务负载都很大。
在应用生命周期之外触发一个操作的典型应用场景是和服务器之间进行同步数据。这种情况你可能想用闹铃,但是如果你有拥有应用数据的服务,使用Goolge Cloud Messaging(GCM)和SyncAdapter比AlarmManager更好。SyncAdapter和AlarmManager有相同的调度选项但更加便利。例如,Sync可能基于设备和服务的新数据消息,用户的活动(或者不活动),时间信息等等。
闹铃在Doze模式下不启动,任何闹铃启动的事务都会在退出Doze模式后调度,所以如果需要确保事务即使设备在闲置状态依然启动,需要使用setAndAllowWhileIdle()或者setExactAndAllowWhileIdle()来保证闹铃的执行。另一个选择是使用WorkManager API,他可以在后台一次或周期调度事务。
最佳实践
每次设计一个重复闹铃都可能对系统有影响(滥用资源)。例如,考虑一个应用与服务器同步。如果同步基于时间并且所有数据都在下午11点同步,服务器负载可能导致严重延迟甚至拒绝服务。所以按照下面的办法使用闹铃:
- 对于重复的闹铃触发的网络请求,添加一个随机(抖动)时间差。
- 闹铃触发时,做任何本地操作, 本地操作即不需要联网的操作。
- 同时,在一个随机的时钟周期调度包含网络请求的闹铃。
- 保证闹铃的频率够低。
- 不要不必要的唤醒设备(是否唤醒设备取决于闹铃的类型)
- 不要使得闹铃触发时间比需要的更精确。
用setInexactRepeating()代替setRepeating()。当使用setInexactRepeating()时,Android同步多个应用的重复闹铃,使他们同时触发。这样能够降低系统被唤醒的总时间,从而省电。随着Android4.4(API19),所有闹铃都时间不精确化了。尽管setInexactRepeating() 比setRepeating()好点,但是如果大量用户几乎同时访问依然会导致服务器负载过重。对于网络请求,添加些随机时间差。
- 尽量避免闹铃基于时间。
基于精确时间的重复闹铃分割的不好,如果可以最好使用ELAPSED_REALTIME。
设置重复闹铃
重复闹铃对调度周期性的任务和数据查询很友好。重复闹铃有如下特点:
- 一个闹铃类型
- 一个触发时间。如果你指定了一个已经过去的时间,闹铃马上发出。
- 闹钟间隔。例如,一天一次,每小时,每5分钟等
- 一个待发intent,在闹铃时间到时发出。如果你设了两个intent,那么第一个会被第二个替代。
选择闹钟类型
如果使用闹钟,首先要考虑的问题就是闹钟类型。
有两个常用类型:“经过时间”和“实时时间(RTC)”。经过时间用自设备启动以来的时间作为参考,实时时间用UTC(挂钟)时间。这意味着经过时间适用于基于时长(例如,每30分钟启动一次的闹铃)的场景,因为这个不需要跟时区挂钩。实时时间更适用于跟地区相关的情景。
这两种类型都有“唤醒”版本,即如果设备进入黑屏则唤醒设备。这能够确保闹钟在期望的时间启动。如果应用是基于时间的这就很有用了,例如,需要在限制的窗口时间内完成某项操作。如果不使用唤醒版本,那么在设备下次唤醒的时候会启动。