介绍

android官方文档:AlarmManager
在Android平台,除了使用AlarmManger外,还可以使用Timer或者Handler来实现定时任务,但这两种方式定时并不会太准确;因此如果我们需要实现精准定时任务,使用AlarmManger更为合理。
AlarmManager类提供对系统闹钟服务(或称为定时器服务)的访问接口,使用它既可以指定单次执行的定时任务,也可以指定重复运行的任务。
当闹钟指定触发时间到达时,实际上是系统发出为这个闹钟注册的广播,因此我们需要实现一个针对特定闹钟事件的广播接口器。
从API 19开始,alarm的机制都是非准确传递,操作系统将会转换闹钟,来最小化唤醒和电池使用。

Note: Beginning with API 19 (KITKAT) alarm delivery is inexact: the OS will shift alarms in order to minimize wakeups and battery use. There are new APIs to support applications which need strict delivery guarantees; see setWindow(int, long, long, PendingIntent) and setExact(int, long, PendingIntent). Applications whose targetSdkVersion is earlier than API 19 will continue to see the previous behavior in which all alarms are delivered exactly when requested.

说明

本文中的代码使用Kotlin来编写,Kotlin是JVM上的一种编程语言,可以与Java无缝对接,由JetBrains公司研发,官方介绍:

Statically typed programming language for the JVM, Android and the browser
100% interoperable with Java™

刚实现定时任务我就写了本文,因此对这方面的知识并没有完全掌握,文中可能会有错误,有机会还会更新。
本文没有将完整的示例代码贴出来,只是贴了关键代码,主要是闹钟的设置和取消,以及与Settings部分的交互。

定时任务实现

常量

首先定义几个常量,包括用于Settings部分的key、用于PendingIntent的requestCode和用于Intent中的action,代码如下:

const val ACTION_ALARM_REPLENISH_STOCK = "witmoon.auto.replenish.stock.action"
const val ACTION_ALARM_SYNCHRONIZE = "witmoon.auto.synchronize.action"
const val ALARM_REPLENISH_STOCK_CODE = 11
const val ALARM_SYNCHRONIZE_CODE = 12const val KEY_SETTING_AUTO_SYNCHRONIZE = "auto_synchronize_status"
const val KEY_SETTING_SYNCHRONIZE_TIME = "auto_synchronize_time"
const val KEY_SETTING_AUTO_SUBMIT = "auto_submit_status"
const val KEY_SETTING_AUTO_SUBMIT_TIME = "auto_submit_time"

BroadcastReceiver

接下来是闹钟事件广播接收器,作为示例代码非常简单,收到广播事件后首先判断action,根据不同的action使用Toast打印出不同的内容:

/** * 闹钟广播接收器 * Created by chuxin on 2016/5/4. */
class AlarmBroadcastReceiver : BroadcastReceiver() {override fun onReceive(context: Context?, intent: Intent?) {var action = intent?.actionwhen {ACTION_ALARM_SYNCHRONIZE.equals(action) -> doSynchronizeAction(context)ACTION_ALARM_REPLENISH_STOCK.equals(action) -> doReplenishStockAction(context)}}private fun doSynchronizeAction(context: Context?) {Toast.makeText(context!!, "同步", Toast.LENGTH_SHORT).show()}/** * 执行补充库存动作, 即下单/定货 */private fun doReplenishStockAction(context: Context?) {Toast.makeText(context!!, "定货", Toast.LENGTH_SHORT).show()}
}

不要忘记在AndroidManifest.xml文件中注册接收器:

<receiver android:name=".receiver.AlarmBroadcastReceiver"><intent-filter><action android:name="witmoon.auto.replenish.stock.action"/><action android:name="witmoon.auto.synchronize.action"/></intent-filter>
</receiver>

设置闹钟

由于我需要在App启动时就设置定时任务,因此我将代码放置到了Application中,并结合了Settings部分重新设置任务执行时间(每天一次),关于Settings部分后面说,此处只关心设置闹钟。

class HomeDoorApplication : Application() {companion object {// 自定义委托实现单例var instance: HomeDoorApplication by DelegatesExt.notNullSingleValue()}override fun onCreate() {super.onCreate()instance = this// 启动定时服务startAlarm()}/** * 启动定时器(使用系统闹铃服务) */private fun startAlarm() {var preferences = PreferenceManager.getDefaultSharedPreferences(this)// 判断是否需要启动定时提交任务var isAutoSubmitEnable = preferences.getBoolean(KEY_SETTING_AUTO_SUBMIT, true)if (isAutoSubmitEnable) {var hourMinuteArray = preferences.getString(KEY_SETTING_AUTO_SUBMIT_TIME, "00:00").split(":")setAlarm(AlarmManager.RTC_WAKEUP, hourMinuteArray[0].toInt(), hourMinuteArray[1].toInt(),AlarmManager.INTERVAL_DAY, ALARM_REPLENISH_STOCK_CODE, ACTION_ALARM_REPLENISH_STOCK)}// 判断是否需要启动定时同步任务var isAutoSynchronizeEnable = preferences.getBoolean(KEY_SETTING_AUTO_SYNCHRONIZE, true)if (isAutoSynchronizeEnable) {var hourMinuteArray = preferences.getString(KEY_SETTING_SYNCHRONIZE_TIME, "00:00").split(":")setAlarm(AlarmManager.RTC_WAKEUP, hourMinuteArray[0].toInt(), hourMinuteArray[1].toInt(),AlarmManager.INTERVAL_DAY, ALARM_SYNCHRONIZE_CODE, ACTION_ALARM_SYNCHRONIZE)}}/** * 取消闹钟 */fun cancelAlarm(requestCode: Int, action: String) {var alarmManager: AlarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManageralarmManager.cancel(PendingIntent.getBroadcast(this, requestCode, Intent(action), PendingIntent.FLAG_UPDATE_CURRENT))}fun setAlarm(type: Int, hour: Int, minute: Int, intervalMillis: Long, requestCode: Int, action: String) {var now = Calendar.getInstance()var targetTime = now.clone() as CalendartargetTime.set(Calendar.HOUR_OF_DAY, hour)targetTime.set(Calendar.MINUTE, minute)targetTime.set(Calendar.SECOND, 0)targetTime.set(Calendar.MILLISECOND, 0)if (targetTime.before(now))targetTime.add(Calendar.DATE, 1)// 方便测试,这里指定即时启动,每20秒执行一次setAlarm(type, 0, 20 * 1000, requestCode, action)
// setAlarm(type, targetTime.timeInMillis, intervalMillis, requestCode, action)}/** * 设置闹钟 */fun setAlarm(type: Int, triggerAtMillis: Long, intervalMillis: Long, requestCode: Int, action: String) {var alarmManager: AlarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManageralarmManager.setRepeating(type, triggerAtMillis, intervalMillis, PendingIntent.getBroadcast(this,requestCode, Intent(action), PendingIntent.FLAG_UPDATE_CURRENT))}
}

这段代码实际上是同时设置了两个定时任务,自动提交订单和自动同步,为了更容易读懂代码,我们只看其中一个就可以。
在startAlarm方法中首先我读取了Settings部分的设置,判断是否需要启动闹钟,如果设置值为true,则去读取设置的任务执行时间;时间格式是每天的几点几分(如22:30表示每天晚上10点半执行)。
读取时间后拆分为小时和分钟,调用setAlarm方法,该方法参数包括闹钟类型、首次触发时间、任务间隔、以及requestCode和Action;在该方法中我使用拆分出的小时和分钟找到该时间点的毫秒数(如果时间在当前时间之前,即触发时间已是过去,则到明天这个时间再触发),调用setAlarm重载方法。
在setAlarm重载方法中,构建出PendingIntent对象并设置好闹钟。

设置

首先看一下最终的设置界面

本文不介绍Settings部分内容,仅仅是记述重新设置任务执行时间的逻辑。
有关Android中Settings部分内容请参考官方文档:Settings

settings.xml

设置界面XML文件,其中用到了一个自定义的Preference用于选择时间,为了不显得太乱这部分代码不再贴出。

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"><PreferenceCategory android:title="同步"><SwitchPreference  android:defaultValue="true" android:key="auto_synchronize_status" android:summary="自动与服务器同步数据" android:title="自动同步"/><com.witmoon.homedoor.ui.preference.TimePickPreference  android:defaultValue="22:30" android:key="auto_synchronize_time" android:summary="每天22点30分" android:title="提交时间"/></PreferenceCategory><PreferenceCategory android:title="下单"><SwitchPreference  android:defaultValue="true" android:key="auto_submit_status" android:summary="开启后会在指定时间点自动提交缺货商品订单" android:title="自动提交订单"/><com.witmoon.homedoor.ui.preference.TimePickPreference  android:defaultValue="23:30" android:key="auto_submit_time" android:summary="每天23点30分" android:title="提交时间"/></PreferenceCategory>
</PreferenceScreen>

SettingFragment

设置部分使用PreferenceFragment,在3.0以后官方建议使用PreferenceFragment来代替PreferenceActivity,定义好SettingFragment后将其放置到一个普通的Activity即可。

class SettingFragment : PreferenceFragment(), SharedPreferences.OnSharedPreferenceChangeListener {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)addPreferencesFromResource(R.xml.setting)}override fun onResume() {super.onResume()preferenceScreen.sharedPreferences.registerOnSharedPreferenceChangeListener(this)}override fun onPause() {super.onPause()preferenceScreen.sharedPreferences.unregisterOnSharedPreferenceChangeListener(this)}// 设置改变响应override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String) {when {KEY_SETTING_AUTO_SYNCHRONIZE.equals(key) -> onAutoSynchronizeChanged(sharedPreferences, key)KEY_SETTING_SYNCHRONIZE_TIME.equals(key) -> onSynchronizeTimeChanged(sharedPreferences, key)KEY_SETTING_AUTO_SUBMIT.equals(key) -> onAutoSubmitChanged(sharedPreferences, key)KEY_SETTING_AUTO_SUBMIT_TIME.equals(key) -> onSubmitTimeChanged(sharedPreferences, key)}}private fun onSubmitTimeChanged(preferences: SharedPreferences?, key: String) {// 取消定时任务HomeDoorApplication.instance.cancelAlarm(ALARM_REPLENISH_STOCK_CODE, ACTION_ALARM_REPLENISH_STOCK)var hourMinuteArray = preferences?.getString(KEY_SETTING_AUTO_SUBMIT_TIME, "00:00")!!.split(":")HomeDoorApplication.instance.setAlarm(AlarmManager.RTC_WAKEUP, hourMinuteArray[0].toInt(),hourMinuteArray[1].toInt(), AlarmManager.INTERVAL_DAY, ALARM_REPLENISH_STOCK_CODE,ACTION_ALARM_REPLENISH_STOCK)}private fun onSynchronizeTimeChanged(preferences: SharedPreferences?, key: String) {// 取消定时任务HomeDoorApplication.instance.cancelAlarm(ALARM_SYNCHRONIZE_CODE, ACTION_ALARM_SYNCHRONIZE)// 设置定时任务var hourMinuteArray = preferences?.getString(KEY_SETTING_SYNCHRONIZE_TIME, "00:00")!!.split(":")HomeDoorApplication.instance.setAlarm(AlarmManager.RTC_WAKEUP, hourMinuteArray[0].toInt(),hourMinuteArray[1].toInt(), AlarmManager.INTERVAL_DAY, ALARM_SYNCHRONIZE_CODE,ACTION_ALARM_SYNCHRONIZE)}// 自动提交订单设置有变化,启用则绑定闹钟,禁用则取消闹钟private fun onAutoSubmitChanged(preferences: SharedPreferences?, key: String) {var isAutoSubmit = preferences?.getBoolean(key, true)!!if (isAutoSubmit) {preferenceScreen.findPreference(KEY_SETTING_AUTO_SUBMIT_TIME).isEnabled = truevar hourMinuteArray = preferences?.getString(KEY_SETTING_AUTO_SUBMIT_TIME, "00:00")!!.split(":")HomeDoorApplication.instance.setAlarm(AlarmManager.RTC_WAKEUP, hourMinuteArray[0].toInt(),hourMinuteArray[1].toInt(), AlarmManager.INTERVAL_DAY, ALARM_REPLENISH_STOCK_CODE,ACTION_ALARM_REPLENISH_STOCK)} else {preferenceScreen.findPreference(KEY_SETTING_AUTO_SUBMIT_TIME).isEnabled = false// 取消定时任务HomeDoorApplication.instance.cancelAlarm(ALARM_REPLENISH_STOCK_CODE, ACTION_ALARM_REPLENISH_STOCK)}}private fun onAutoSynchronizeChanged(preferences: SharedPreferences?, key: String) {var isAutoSynchronize = preferences?.getBoolean(key, true)!!if (isAutoSynchronize) {preferenceScreen.findPreference(KEY_SETTING_SYNCHRONIZE_TIME).isEnabled = true// 设置定时任务var hourMinuteArray = preferences?.getString(KEY_SETTING_SYNCHRONIZE_TIME, "00:00")!!.split(":")HomeDoorApplication.instance.setAlarm(AlarmManager.RTC_WAKEUP, hourMinuteArray[0].toInt(),hourMinuteArray[1].toInt(), AlarmManager.INTERVAL_DAY, ALARM_SYNCHRONIZE_CODE,ACTION_ALARM_SYNCHRONIZE)} else {preferenceScreen.findPreference(KEY_SETTING_SYNCHRONIZE_TIME).isEnabled = false// 取消定时任务HomeDoorApplication.instance.cancelAlarm(ALARM_SYNCHRONIZE_CODE, ACTION_ALARM_SYNCHRONIZE)}}
}

SharedPreferences.OnSharedPreferenceChangeListener接口用于监听设置项的改变,从代码中可以看出,如果是关闭自动任务,则直接调用取消闹钟;如果是重新设置了任务执行时间,则先取消闹钟,再用新的时间重新设置闹钟。取消和设置都在前面的Application中定义了,这里只是简单地调用即可。

转自:https://my.oschina.net/zhyihui/blog/711327

使用AlarmManager实现Android应用每天定时执行任务相关推荐

  1. android 定时闹钟逻辑,Android 定时执行任务 AlarmManager的使用(可用于闹钟开发)...

    Android 定时执行任务 AlarmManager的使用(可用于闹钟开发) 2011年7月13日加注:所有的定时任务在手机重启后会消失,如果需要重启后继续用,可以加个开机自启,然后重新设置. Al ...

  2. android使用AlarmManager实现应用每天定时执行任务

    简介: 关于service 大家应都知道是Android 四大组件之一,用来执行后台任务的.Android 中的定时任务一般有两种实现方式,一种是使用Java API 里提供的Timer 类,一种是使 ...

  3. android alarmmanager后台,Android AlarmManager实现定时循环后台任务

    这篇文章使用AlarmManager实现了Android定时后台循环任务.使用场景:项目需要app每隔一段时间就去服务端请求一次接口,从而更新本地保存的信息. AlarmManager简介 Alarm ...

  4. android 一个activity定时更新另一个activity的UI

    在开发软件的过程中,客户提出了一个要求,就是在Mainactivity的一个按键button按下之后进入另一个OtherActivity,在这个OtherActivity完成了功能之后,按键butto ...

  5. android 自动发彩信,Android编程实现定时发短信功能示例

    本文实例讲述了Android编程实现定时发短信功能.分享给大家供大家参考,具体如下: 第一,要实现发短信的功能,必须要用到android系统中发短信的权限,即在AndoridManifest.xml中 ...

  6. android+发短信示例,Android编程实现定时发短信功能示例

    本文实例讲述了Android编程实现定时发短信功能.分享给大家供大家参考,具体如下: 第一,要实现发短信的功能,必须要用到android系统中发短信的权限,即在AndoridManifest.xml中 ...

  7. linux定时执行任务命令,crontab(linux下定时执行任务命令)

    在linux在可以通过在脚本里(列如sh)写如日常需要进行的操作,然后通过crontab定时运行脚本. Linux下的任务调度分为两类,系统任务调度和用户任务调度. 系统任务调度:系统周期性所要执行的 ...

  8. Android App 可以定时启动! 并且完成短信自动发送获取内容功能 (以获取闪讯密码为例 大学宿舍宽带)

    接上一篇:android 发送短信sendTextMessage()真机运行报错,退出,在已申请SEND_SMS权限的情况下Android send SMS not working uid ... 重 ...

  9. Android App 可以定时启动! 并且完成短信自动发送获取内容功能 (以获取闪讯密码为例 大学宿舍宽带)

    接上一篇:android 发送短信sendTextMessage()真机运行报错,退出,在已申请SEND_SMS权限的情况下Android send SMS not working uid ... 重 ...

最新文章

  1. react项目中使用mocha结合chai断言库进行单元测试
  2. 浅谈:稀疏数组与二维数组之间的转换
  3. Linux 中常见的较为复杂的命令实例
  4. 工作笔记-SDRAM的读写
  5. LeetCode 1481. 不同整数的最少数目(计数+排序+贪心)
  6. Spark3.0发布了,代码拉过来,打个包,跑起来!| 附源码编译
  7. shell脚本练习题
  8. Linux Performance Observability Tools
  9. java并发面试题整理
  10. Hibernate存取JSON数据
  11. 用c语言编写一个打勾的图形,C语言图形编程.ppt
  12. NTFS, FAT32和exFAT文件系统有什么区别
  13. leaflet地图原理_Leaflet地图框架使用手册
  14. cad横断面图转文本
  15. 汉诺塔_-Chaz-_新浪博客
  16. Sam Altman 山姆奥特曼:强化学习进展 Reinforcement Learning Progress
  17. 郑州大学计算机系1996级校友,公共管理学院成功举办96级公共关系专业学生毕业20周年返校活动...
  18. DAMO-YOLO | 超越所有YOLO,5行代码即可体验
  19. 分销的概念、本质、模式
  20. Linux安装conda未找到命令

热门文章

  1. 三维建模 Cinema 4D
  2. Pandas基础学习入门级别
  3. 高级编程语言高级在哪里?
  4. 企业上云,就上...
  5. android 串口 wifi模块,一文深度了解串口WiFi模块的应用场景
  6. 华硕ROG玩家国度安装Ubuntu20.04,安装过程一直卡着不动,以及快捷键不能用,不能调节键盘亮度等问题的解决办法,另附上安装Ubuntu18.04的方法
  7. C语言qsort函数的使用,及自己实现的qsort函数
  8. 计算机专业262分,一战初试262分!第一名录取对外经贸全日制MPAcc的秘密!
  9. signature=e9c3e111e2374143dfad8bd5f3d2024c,XFA: Faster Signature Matching with Extended Automata
  10. 微信小程序考勤系统的目的和功能