Android 轮询最佳实践 Service + AlarmManager

后台执行的定时任务

AlarmManager的正确使用姿势

Android-AlarmManagerClock

关于Android中设置闹钟的相对完善的解决方案

定时任务,AlarmManager使用

Android---AlarmManager(全局定时器/闹钟)指定时长或以周期形式执行某项操作

AlarmManager的常用API

[ANDROID 開發筆記] SCHEDULING REPEATING ALARMS 範例教學 (鬧鐘,定時器)

MiUI AlarmManager 延迟

set(int type, long triggerAtMillis, PendingIntent operation)

该方法用于设置一次性闹钟,第一个参数表示闹钟类型,第二个参数表示闹钟执行时间,第三个参数表示闹钟响应动作。

setRepeating(int type, long triggerAtMillis,long intervalMillis, PendingIntent operation)

该方法用于设置重复闹钟,第一个参数表示闹钟类型,第二个参数表示闹钟首次执行时间,第三个参数表示闹钟两次执行的间隔时间,第四个参数表示闹钟响应动作。

setInexactRepeating(int type, long triggerAtMillis,long intervalMillis, PendingIntent operation)

该方法也用于设置重复闹钟,与第二个方法相似,不过闹钟时间不精确。

setExact(int type, long triggerAtMillis, PendingIntent operation)
setWindow(int type, long windowStartMillis, long windowLengthMillis,PendingIntent operation)

方法1和方法2在SDK_INT 19以前是精确的闹钟,19以后为了节能省电(减少系统唤醒和电池使用)。使用Alarm.set()和Alarm.setRepeating()已经不能保证精确性,不过还好Google又提供了两个精确的Alarm方法setWindow()和setExact(),所以19以后需要精确的闹钟就需要上面两个方法,具体原因后面再说

cancel(PendingIntent operation)

取消Intent相同的闹钟,这里是根据Intent中filterEquals(Intent other)方法来判断是否相同

public boolean filterEquals(Intent other) {
        if (other == null) {
            return false;
        }
        if (!Objects.equals(this.mAction, other.mAction)) return false;
        if (!Objects.equals(this.mData, other.mData)) return false;
        if (!Objects.equals(this.mType, other.mType)) return false;
        if (!Objects.equals(this.mPackage, other.mPackage)) return false;
        if (!Objects.equals(this.mComponent, other.mComponent)) return false;
        if (!Objects.equals(this.mCategories, other.mCategories)) return false;


        return true;
    }

从方法体可以看出mAction、mData、mType、mPackage、mComponent、mCategories这几个完全一样就认定为同一Intent

闹钟类型

这个闹钟类型就是前面setxxx()方法第一个参数int type.

  • AlarmManager.ELAPSED_REALTIME :使用相对时间,可以通过SystemClock.elapsedRealtime() 获取(从开机到现在的毫秒数,包括手机的睡眠时间),设备休眠时并不会唤醒设备。
  • AlarmManager.ELAPSED_REALTIME_WAKEUP :与ELAPSED_REALTIME基本功能一样,只是会在设备休眠时唤醒设备。
  • AlarmManager.RTC :使用绝对时间,可以通过 System.currentTimeMillis()获取,设备休眠时并不会唤醒设备。
  • AlarmManager.RTC_WAKEUP : 与RTC基本功能一样,只是会在设备休眠时唤醒设备。

FAQQ1. 设定多个定时闹钟为什么只有最后一个生效

A: AlarmManager 根据 PendingIntent requestCode 来判断是否是同一个定时服务,所以当

requestCode相等的时候只有最后一个生效

1. 我们说的requestCode 是第二个参数


PendingIntent.getBroadcast(Context context, int requestCode, Intent intent, @Flags int flags)


2. 例如:


PendingIntent pi1 = PendingIntent.getBroadcast(this, 1, intent, 0); 
AlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, startTime, intervalTime, pi1);  


PendingIntent pi2 = PendingIntent.getBroadcast(this, 2, intent, 0); 
AlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, startTime, intervalTime, pi2); 


这个样子就可以设定2个了

AlarmManager 最少只能每5秒执行一次操作,所以不能每秒钟都更新一次,如果需要显示秒数,可以使用 handle 的 postDelay 方法来实现

最后一个建议:

在调用setRepeating安排定时器之前,最好检查定时器是否已经在运行,像这样:

if (isServiceAlarmOn(this)) {
    alarmManager.setRepeating(AlarmManager.RTC, 
            System.currentTimeMillis(), POLL_INTERVAL, pi);
} else {
    // 取消Alarm,同时取消PendingIntent.
    alarmManager.cancel(pi);
    pi.cancel();
}


// 由于在取消Alarm的同时也取消了pi,并且一个PendingIntent只能登记给一个Alarm,
// 所以可通过检查pi是否存在,来确认Alarm是否激活。
public static boolean isServiceAlarmOn(Context context) {
    Intent i = new Intent(context, PollService.class);
    // FLAG_NO_CREATE表示如果描述的pi不存在,则返回null,而不是创建它。
    PendingIntent pi = PendingIntent.getService(
            context, 0, i, PendingIntent.FLAG_NO_CREATE);
    return pi != null;
}

results matching ""

    No results matching ""