AlarmManager 定时任务

  • 使用场景
  • API
    • 1.设置定时任务
      • 1.1.单次定时任务 (set)
      • 1.2.设置在时间段执行的定时任务(setWindow)
      • 1.3.设置单次准确的定时任务(setExact 、setAlarmClock)
      • 1.4.设置在低功耗条件下也执行的定时任务 (setAndAllowWhileIdle、setExactAndAllowWhileIdle)
      • 1.5.设置循环的定时任务(setRepeating、setInexactRepeating)
      • 1.6.设置定时任务的方法如何选择?
      • 1.7.系统为我们做了版本兼容的封装
    • 2.剩余
      • 2.1.取消闹钟设置
      • 2.2.获取下次闹钟
      • 2.3.设置系统时间
      • 2.4.设置系统时间时区
  • 版本变更记录
  • 参考地址

使用场景

设置闹铃
发送心跳包

API

1.设置定时任务

功能说明:
设置一个在未来的某个时间运行应用的PendingIntent 或者OnAlarmListener ,即使设备已经进入睡眠(Cpu休眠)已设置的闹铃也会被保持,只有当设备关闭或是重启的时候会被清除

1.1.单次定时任务 (set)

void set(@AlarmType int type, long triggerAtMillis, PendingIntent operation)
void set(@AlarmType int type, long triggerAtMillis, String tag, OnAlarmListener listener, Handler targetHandler)

含义:
设置一个闹钟,这个闹钟设置在API 19以下是准确的,API 19及以上因为系统的优化(系统要批量处理这些闹钟以减少唤醒次数,减少电池的使用),不再准确。如果想在API 19及以上的版本依然准备需要使用 setWindow 或者 setExact 。

API翻译:

安排警报。<b>注意:对于计时操作(滴答声、超时等),使用{@linkandroid.os.Handler}更容易、更高效。
如果已经为同一个IntentSender安排了一个警报,则之前的警报将首先被取消。
如果规定的触发时间是过去的,则会立即触发报警。
如果已经计划了此意图的警报(由{@link Intent#filterEquals}定义两个意图相等),则将删除该警报并替换为此警报。
报警是一种意图广播,发送到您在{@link android.content.Context#registerReceiver}注册的广播接收器,或通过&lt;接收器(&gt);AndroidManifest中的标记。xml文件。报警意图与类型为int的额外数据一起传递,该数据称为{@link Intent#EXTRA_ALARM_COUNT Intent.EXTRA_ALARM_COUNT} ,指示有多少过去的报警事件累积到此意图广播中。由于手机处于睡眠状态而无法发送的重复报警在发送时的计数可能大于1。<b>注:从API 19开始,传递给此方法的触发时间被视为不精确:在此时间之前不会发出警报,但可能会推迟一段时间并在稍后发出。
操作系统将使用此策略在整个系统中“批量”报警,
将设备需要“唤醒”的次数降至最低,并将电池使用降至最低。
一般来说,只要计划在遥远的将来进行报警,则不会延迟计划在不久的将来进行的报警。
有了新的批处理策略,交货订单保证不如以前那么有力。
如果应用程序设置了多个警报,则这些警报的实际交付顺序可能与其请求的交付时间顺序不匹配。
如果您的应用程序有很强的排序需求,那么您可以使用其他API来获得必要的行为;
请参阅{@link #setWindow(int, long, long, PendingIntent)}和 {@link #setExact(int, long, PendingIntent)}.{@code targetSdkVersion}在API 19之前的应用程序将继续获得以前的报警行为:所有计划的报警都将被视为精确的。

参数:

参数 @AlarmType int type
事件参照物,以及是否在休眠时唤起//时间参照物是当前系统时间,并且唤醒CPUpublic static final int RTC_WAKEUP = 0;//时间参照物是当前系统时间,不唤醒CPUpublic static final int RTC = 1;//时间参照物是系统到目前的时间(包括系统休眠),且唤醒CPUpublic static final int ELAPSED_REALTIME_WAKEUP = 2;//时间参照物是系统到目前的时间(包括系统休眠),不唤醒CPUpublic static final int ELAPSED_REALTIME = 3;参数 long triggerAtMillis
触发执行的时间参数  PendingIntent operation
挂起的意图

测试代码

    @Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_alarm);AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);Intent intent = new Intent();intent.setClass(this, AlarmActivity.class);intent.setAction("这是set过来的intent");PendingIntent pi = PendingIntent.getActivity(this, 0, intent, 0);alarmManager.cancel(pi);int interval = 5 * 1000;findViewById(R.id.btn_test_1).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {AppLogUtils.input(TAG, "onClick btn_test_1");alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + interval, pi);}});****}@Overrideprotected void onNewIntent(Intent intent) {super.onNewIntent(intent);AppLogUtils.input(TAG, "onNewIntent");AppLogUtils.input(TAG, "onNewIntent.getAction == " + intent.getAction());((TextView) findViewById(R.id.tv_content)).setText(intent.getAction());}

最终成功调用到 onNewIntent(),此时设置 android:launchMode=“singleTask”

1.2.设置在时间段执行的定时任务(setWindow)

void setWindow(@AlarmType int type, long windowStartMillis, long windowLengthMillis,PendingIntent operation)
void setWindow(@AlarmType int type, long windowStartMillis, long windowLengthMillis,String tag, OnAlarmListener listener, Handler targetHandler)

含义:
如果SDK版本在 Android 4.4 (Api 19)=< SDK < Android 6.0 (Api 23)这个区间,我们对闹钟的时序性要求较高,但是对及时性要求不高时,可以使用 setWindow 。

setWindow 不会让闹钟被系统批量处理(如set方法),而是按照设置的先后顺序处理(严格的排序保证),但是同时setWindow 的闹钟及时性不准确。

翻译API:

 安排在给定时间窗口内发出警报。此方法类似于{@link#set(int,long,PendingIntent)},但允许应用程序精确控制操作系统可能调整其交付的程度。这种方法允许应用程序利用交付批处理产生的电池优化,即使它对警报的及时性要求不高。此方法还可用于通过确保每个报警请求的窗口不相交,在多个报警之间实现严格的排序保证。当不需要精确传递时,应用程序应该使用标准的{@link#set(int,long,PendingIntent)}方法。这将为操作系统提供最大的灵活性,以最小化唤醒和电池使用。对于必须在精确指定的时间发出且没有可接受的变化的报警,应用程序可以使用{@link#setExact(int,long,PendingIntent)}。

参数:

参数 long windowStartMillis
触发执行的时间段左边界参数 long windowLengthMillis
时间段长度

测试代码:

alarmManager.setWindow(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + interval, interval, pi);

1.3.设置单次准确的定时任务(setExact 、setAlarmClock)

void setExact(@AlarmType int type, long triggerAtMillis, PendingIntent operation)
void setExact(@AlarmType int type, long triggerAtMillis, String tag,OnAlarmListener listener, Handler targetHandler)void setAlarmClock(AlarmClockInfo info, PendingIntent operation)

setExact 含义:

如果SDK版本在 Android 4.4 (Api 19)=< SDK < Android 6.0 (Api 23)这个区间,我们对闹钟的时序性要求较高,同时要求及时性要求也高时,可以使用 setExact 。

setExact 不会让闹钟被系统批量处理(如set方法),而是按照设置的先后顺序处理(严格的排序保证),同时setExact 的闹钟及时性准确。

翻译API:

安排在规定的时间准确发出警报。
此方法类似于{@link#set(int,long,PendingIntent)},但不允许操作系统调整传递时间。
警报将尽可能接近请求的触发时间。
<b>注意:</b>只有对准确时间交付有强烈需求的报警(如在请求的时间闹钟响)才应安排为准确。
强烈建议应用程序不要不必要地使用精确警报,因为它们会降低操作系统将电池使用降至最低的能力。

setAlarmClock 含义:

SDK版本在 大于 Android 4.4 (Api 19),都可以使用 setAlarmClock

指定闹钟事件AlarmManager.setAlarmClock()的事件会在闹钟结束前,令系统短暂的完全退出Doze模式,并且正常处理事件,系统为了突显该闹钟事件,将会在status bar上显示物理闹钟的icon。

翻译API:

安排一个代表闹钟的闹钟,该闹钟将用于在闹钟熄灭时通知用户。我们的期望是,当该警报触发时,
该应用程序将进一步唤醒设备,告诉用户有关警报的信息——打开屏幕、播放声音、振动等。
因此,如果合适,系统通常还会使用此处提供的信息告知用户即将发生的警报。由于这种报警的性质类似于{@link#setExactAndAllowHileidle},即使系统处于低功率闲置(又称打盹)模式,也允许触发这些警报。当系统看到出现此类警报时,也可能会进行一些准备工作,
为了减少在导致设备完全唤醒时可能发生的后台工作量,这是为了避免出现大量设备在早上的同一时间设置了警报的情况,
所有人都在那个时候醒来,突然间,网络上充斥着悬而未决的背景工作。
因此,这些类型的报警器在电池使用上可能非常昂贵,并且只能用于其预期用途。此方法类似于{@link#setExact(int,long,PendingIntent)},但暗指{@link#RTC_WAKEUP}。

1.4.设置在低功耗条件下也执行的定时任务 (setAndAllowWhileIdle、setExactAndAllowWhileIdle)

Android 6.0 (Api 23)及以上,系统新增低功耗空闲(又称doze)模式,
这种模式下setExact 和 setWindow 方法失效,因为不能唤醒系统,除此模式以外的场景,依然是准确的。

如果想打破这种限制,可以唤醒系统,需要使用 setAndAllowWhileIdle 或者 setExactAndAllowWhileIdle。

setAndAllowWhileIdle 含义:

setAndAllowWhileIdle 设置的警报可以被批量处理,低功耗空闲(又称doze)模式下,准确度更低。

翻译API:

与{@link#set(int,long,PendingIntent)}类似,但即使系统处于低功耗空闲(又称doze)模式,也允许执行此警报。
这种类型的警报必须仅用于实际需要在空闲时发出警报的情况——一个合理的例子是日历通知,它应该发出声音,以便用户知道。
当警报发出时,该应用程序还将被添加到系统的临时白名单中约10秒,以允许该应用程序获取进一步的唤醒锁,从而完成其工作。当设备闲置时,这些警报可能会严重影响设备的电源使用(从而导致调度警报的应用程序严重的电池故障),因此应谨慎使用。
为了减少滥用,对特定应用程序发出警报的频率有限制。
在正常系统运行情况下,其发出这些警报的时间不会超过大约每分钟一次(此时发出所有此类待处理警报);
在低功率怠速模式下,此持续时间可能会明显更长,例如15分钟。与其他警报不同,该系统可以自由地重新安排此类警报与任何其他警报(甚至来自同一应用程序的警报)无序发生。
当设备空闲时,这显然会发生(因为此警报可以在空闲时熄灭,当应用程序的任何其他警报将保持到稍后),但即使在不空闲时也可能发生。无论应用程序的目标SDK版本如何,此调用始终允许成批处理警报。

setExactAndAllowWhileIdle含义:

setExactAndAllowWhileIdle 也可以唤醒系统,和 setAndAllowWhileIdle 对比准确度更高,不会被系统批量处理。

翻译API:

与{@link#setExact(int,long,PendingIntent)}类似,但即使系统处于低功耗空闲模式,也允许执行此警报。
如果不需要精确的警报调度,但仍需要在空闲时执行,请考虑使用{@link#setAndAllowWhileIdle}。
这种类型的警报必须仅用于实际需要在空闲时发出警报的情况——一个合理的例子是日历通知,它应该发出声音,以便用户知道。
当警报发出时,该应用程序还将被添加到系统的临时白名单中约10秒,以允许该应用程序获取进一步的唤醒锁,从而完成其工作。当设备闲置时,这些警报可能会严重影响设备的电源使用(从而导致调度警报的应用程序严重的电池故障),因此应谨慎使用。
为了减少滥用,对特定应用程序发出警报的频率有限制。
在正常系统运行情况下,其发出这些警报的时间不会超过大约每分钟一次(此时发出所有此类待处理警报);
在低功率怠速模式下,此持续时间可能会明显更长,例如15分钟。与其他警报不同,该系统可以自由地重新安排此类警报与任何其他警报(甚至来自同一应用程序的警报)无序发生。
当设备空闲时,这显然会发生(因为此警报可以在空闲时熄灭,当应用程序的任何其他警报将保持到稍后),但即使在不空闲时也可能发生。请注意,由于应用程序选择了这种行为,因此操作系统将允许自己比常规的精确报警更灵活地安排这些报警。
当设备空闲时,为了优化电池寿命,可能需要更多的时间安排。

1.5.设置循环的定时任务(setRepeating、setInexactRepeating)

//循环定时,时间准确
void setRepeating(@AlarmType int type, long triggerAtMillis,long intervalMillis, PendingIntent operation)
//循环定时,时间不准确
void setInexactRepeating(@AlarmType int type, long triggerAtMillis,long intervalMillis, PendingIntent operation)

setRepeating、setInexactRepeating()方法用于Android 4.4(Api 19)以下,大于19的版本可以使用变通的方案:setExactAndAllowWhileIdle + pendintent.getBroadcast

1.6.设置定时任务的方法如何选择?

如果你期望每次都是按照你的设想响应定时任务:

小于 API 19 :
set、setRepeating、setInexactRepeating

大于等于 API 19 小于 API 23:
setWindow、setExact 、setAlarmClock

大于 API 23:
如果想要在低功耗空闲(又称doze)模式下使用
setAndAllowWhileIdle、setExactAndAllowWhileIdle、setAlarmClock

但是这样会更影响电池的使用时长,非必要可以不这么选择。

1.7.系统为我们做了版本兼容的封装

https://developer.android.google.cn/reference/androidx/core/app/AlarmManagerCompat


public final class AlarmManagerCompat {public static void setAlarmClock(@NonNull AlarmManager alarmManager, long triggerTime,@NonNull PendingIntent showIntent, @NonNull PendingIntent operation) {if (Build.VERSION.SDK_INT >= 21) {alarmManager.setAlarmClock(new AlarmManager.AlarmClockInfo(triggerTime, showIntent),operation);} else {AlarmManagerCompat.setExact(alarmManager, AlarmManager.RTC_WAKEUP, triggerTime,operation);}}public static void setAndAllowWhileIdle(@NonNull AlarmManager alarmManager, int type,long triggerAtMillis, @NonNull PendingIntent operation) {if (Build.VERSION.SDK_INT >= 23) {alarmManager.setAndAllowWhileIdle(type, triggerAtMillis, operation);} else {alarmManager.set(type, triggerAtMillis, operation);}}public static void setExact(@NonNull AlarmManager alarmManager, int type, long triggerAtMillis,@NonNull PendingIntent operation) {if (Build.VERSION.SDK_INT >= 19) {alarmManager.setExact(type, triggerAtMillis, operation);} else {alarmManager.set(type, triggerAtMillis, operation);}}public static void setExactAndAllowWhileIdle(@NonNull AlarmManager alarmManager, int type,long triggerAtMillis, @NonNull PendingIntent operation) {if (Build.VERSION.SDK_INT >= 23) {alarmManager.setExactAndAllowWhileIdle(type, triggerAtMillis, operation);} else {AlarmManagerCompat.setExact(alarmManager, type, triggerAtMillis, operation);}}private AlarmManagerCompat() {}
}

2.剩余

2.1.取消闹钟设置

cancel

2.2.获取下次闹钟

getNextAlarmClock

2.3.设置系统时间

setTime

2.4.设置系统时间时区

setTimeZone

版本变更记录

版本4.4(19)变更说明:https://developer.android.google.cn/about/versions/android-4.4

如果您的应用使用 AlarmManager…
将您的应用的 targetSdkVersion 设置为“19”或更高版本时,您使用 set() 或 setRepeating() 创建的闹铃将变得不准确。
为提高电源效率,Android 现在批处理在合理的相似时间发生的所有应用的闹铃,以便系统仅唤醒设备一次,而不是多次唤醒设备来处理每个闹铃。
如果您的闹铃没有与精确的时钟时间关联,但您的闹铃仍必须在特定时间范围(例如,在下午 2 点至 4 点之间)触发,那么您可以使用新的 setWindow() 方法,其接受闹铃的“最早”时间以及最早时间之后的一个时间“窗口”,在这个窗口内,系统应触发闹铃。
如果您的闹铃必须固定到一个精确的时钟时间(例如,日历事件提醒),那么您可以使用新的 setExact() 方法。
这个精确的批处理行为仅适用于更新后的应用。如果您已将 targetSdkVersion 设置为“18”或更低版本,那么在 Android 4.4 上运行时,您的闹铃的行为方式和在以前版本上一样。

Android 6.0 针对低电耗模式和应用待机模式进行优化:https://developer.android.google.cn/training/monitoring-device-state/doze-standby

在低电耗模式下,您的应用会受到以下限制:
标准 AlarmManager 闹钟(包括 setExact() 和 setWindow())推迟到下一个维护期。
如果您需要设置在设备处于低电耗模式时触发的闹钟,请使用 setAndAllowWhileIdle() 或 setExactAndAllowWhileIdle()。
使用 setAlarmClock() 设置的闹钟将继续正常触发,系统会在这些闹钟触发之前不久退出低电耗模式。

*使应用适应低电耗模式
低电耗模式可能会对应用产生不同的影响,具体取决于应用提供的功能和使用的服务。许多应用无需修改即可在低电耗模式周期内正常运行。在某些情况下,您必须优化应用管理网络、闹钟、作业和同步的方式。应用应该能够在每个维护期内高效地管理活动。
低电耗模式尤其可能会影响 AlarmManager 闹钟和定时器管理的活动,因为当系统处于低电耗模式时,不会触发 Android 5.1(API 级别 22)或更低版本中的闹钟。
为了帮助安排闹钟,Android 6.0(API 级别 23)引入了两种新的 AlarmManager 方法:setAndAllowWhileIdle() 和 setExactAndAllowWhileIdle()。通过这些方法,您可以设置即使设备处于低电耗模式也会触发的闹钟。
注意:setAndAllowWhileIdle() 及 setExactAndAllowWhileIdle() 为每个应用触发闹钟的频率都不能超过每 9 分钟一次。

参考地址

AlarmManager 定时任务详解:https://blog.csdn.net/kingyc123456789/article/details/107179126

AlarmManager(系统服务之定时服务):https://blog.csdn.net/wuto_/article/details/110494026

Android后台调度任务与省电:https://www.ktanx.com/blog/p/4827

记录每天学习的新知识:AlarmManager 定时任务相关推荐

  1. 记录每天学习的新知识:MQTT客户端

    Android - MQTT客户端 什么是MQTT Android 客户端的使用 操作1.创建新连接 - newClient 操作2.设置参数 - setClientConfig 操作3.连接 - c ...

  2. 记录每天学习的新知识:Composing builds

    Composing builds 一.啥是 Composing builds ?? 二.使用 1. 于项目中新建 Moudle,取名 VersionPlugin 2.重写 VersionPlugin ...

  3. 记录每天学习的新知识:LiveData

    LiveData 前言 LiveData 使用 LiveData 的优势 使用 更新 转换 合并 扩展 - 自定义LiveData 参考地址 前言 Jetpack 是一个丰富的组件库,它的组件库按类别 ...

  4. 记录每天学习的新知识:DataBinding

    DataBinding 前言 使用前需要了解 一.基础用法 二.引入布局(include.viewStub) 三.单向绑定 (Data变化通知View) 1.BaseObservable 2.Obse ...

  5. 记录每天学习的新知识:ViewModel

    ViewModel 特点: 使用场景: 应用事例: 支持协程 参考地址 特点: 单一职责,将数据从业务中抽离出来.即只要是界面上看的到的数据,相关变量都应该存放在ViewModel,而不是Activi ...

  6. 记录每天学习的新知识:ARouter

    ARouter 前言 一.引用和初始化 二.跳转功能 三.支持跳转携带参数 四.支持URL跳转 五.Fragment跳转 六.实现 startActivityForResult 跳转 七.分组 八.拦 ...

  7. 记录每天学习的新知识:MotionEvent

    MotionEvent getAction MotionEvent.ACTION_DOWN MotionEvent.ACTION_UP MotionEvent.ACTION_MOVE MotionEv ...

  8. 【每天学习一点新知识】中间人攻击是什么

    目录 中间人攻击介绍 中间人攻击原理 1. ARP欺骗 2. DNS欺骗 防御方法 中间人攻击介绍 中间人攻击(man-in-the-middle attack, abbreviated to MIT ...

  9. 每天学习一点新知识(一)——Unity开发游戏的拆包

    每天学习一点新知识(一)--Unity开发游戏的解包 用了CSDN有一段时间了,但一直都没有写过blog,只是在输入,没有输出.而且一直主要都是在查一些作业.题解什么的,还是希望自己能够多学到一些新东 ...

最新文章

  1. Struts Web应用程序开发步骤
  2. 重学TCP协议(10)SYN flood 攻击
  3. docker 容器 日志_如何为Docker容器设置日志轮换
  4. JVM :执行jinfo命令报错Can't attach symbolicator to the process
  5. C# 用IrisSkin4.dll美化你的WinForm
  6. java怎么实现打牌_JAVA入门第三季实战:简易扑克牌
  7. etl构建数据仓库五步法_构建数据仓库五步法
  8. admin is not in the sudoers file. This incident will be reported
  9. python游戏设计的课题背景_游戏设计论文开题报告
  10. android自动计步_Android计步模块(类似微信运动)
  11. 杭州旅游全攻略,详细!
  12. 商务网站建设与维护【12】
  13. linux下chm制作工具,在Linux上安装CHM查看工具
  14. python画爱心 好看漂亮的表白代码
  15. 【_ 記 】SpringBoot注解 (最新最全最详细)
  16. 百度竞价排名曝光_全球塑胶网:百度爱采购模式推广效果怎么样?
  17. 从IPv4到IPv6那消失的IPv5哪去了?
  18. 第18节--python文件读写
  19. html5取消下拉菜单,Vue.js实现在下拉列表区域外点击即可关闭下拉列表的功能(自定义下拉列表)...
  20. 前端:request.js?b775:105 Uncaught (in promise) Error: nested exception is org.apache.ibatis.exceptions

热门文章

  1. 转载 | 身份访问与管理(IAM)的定义、应用与提供商
  2. 常用小工具:一款好用、实用的“日常工作安排”桌面日历
  3. 【太虚AR_v0.1】使用教程 | 视频播放
  4. matlab 元胞自动机
  5. python安装第三方包的几种方式
  6. 自建OTA服务器实现设备固件自动更新
  7. XAML C# WPF
  8. java按钮权限控制_aop (权限控制之功能权限)
  9. iOS开发笔记(IOS7回归)
  10. 【Python习题】简易英汉字典(project-ssss)(题目的坑解析+实现代码)