- AlarmManager提供对系统alarm服务的访问。
- Alarm Manager在alarm receiver的onReceive()方法执行期间持有一个CPU唤醒锁,以保证完成处理广播。方法返回,则释放唤醒锁,设备即可睡去。
- 这导致,如果你在处理广播时调用了Context.startService(),则手机可能会在服务起来之前睡去。所以必须实现独立的唤醒锁策略,使手机在服务起来之前保持运转。
- Alarm Manager主要用来使你的程序代码在指定的事件运行,即使你的应用当前没有运行。其它普通的计时操作用Handler来实现更为简便高效。
- Context.getSystemService(Context.ALARM_SERVICE)
.
几个常量:
- AlarmManager.RTC_WAKEUP: 唤醒设备,按System.currentTimeMills()计时
- AlarmManager.RTC:不唤醒设备,直到设备下次被唤醒时才发送
- AlarmManager.ELAPSED_REALTIME_WAKEUP:到时唤醒设备,按开机时间计时
- AlarmManager.ELAPSED_REALTIME:按开机时间计时,其余同2
提供的方法:
- 设置一个闹钟
void set(int type, long triggerAtMillis, PendingIntent operation) |
void setInexactRepeating(int type, long triggerAtMillis, long intervalMillis, PendingIntent operation) |
void setRepeating(int type, long triggerAtMillis, long intervalMillis, PendingIntent operation) |
void setTime(long millis) |
void setTimeZone(String timeZone) |
cancel(PendingIntent operation) |
- 唤醒锁是一种让设备保持唤醒的机制
- 使用它需要权限:android.permission.WAKE_LOCK
- 用完立即释放
- 用法
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "My Tag"); wl.acquire(); ..screen will stay on during this section.. wl.release();
Email应用通过一个名叫MailService的服务来进行邮件帐户的刷新操作:
if (ACTION_CHECK_MAIL.equals(action)) {
// DB access required to satisfy this intent, so offload from UI thread
EmailAsyncTask.runAsyncParallel(new Runnable() {
@Override
public void run() {
...
// 设置一个看门狗
if (accountId >= 0) {
setWatchdog(accountId, alarmManager);
}
// 对帐户进行同步
syncStarted = syncOneAccount(mController, accountId,
...
// 设置下一个要同步的帐户
reschedule(alarmManager);
// Stop the service, unless actually syncing (which will stop the service)
stopSelf(startId);
}
}
});
}
/**
* Create a watchdog alarm and set it. This is used in case a mail check fails (e.g. we are
* killed by the system due to memory pressure.) Normally, a mail check will complete and
* the watchdog will be replaced by the call to reschedule().
* @param accountId the account we were trying to check
* @param alarmMgr system alarm manager
*/
private void setWatchdog(long accountId, AlarmManager alarmMgr) {
PendingIntent pi = createAlarmIntent(accountId, null, true);
long timeNow = SystemClock.elapsedRealtime();
long nextCheckTime = timeNow + WATCHDOG_DELAY;
alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextCheckTime, pi);
}
/**
* Create and send an alarm with the entire list. This also sends a list of known last-sync
* times with the alarm, so if we are killed between alarms, we don't lose this info.
*
* @param alarmMgr passed in so we can mock for testing.
*/
private void reschedule(AlarmManager alarmMgr) {
...
synchronized (mSyncReports) {
...
// set/clear alarm as needed
long idToCheck = (nextAccount == null) ? -1 : nextAccount.accountId;
PendingIntent pi = createAlarmIntent(idToCheck, accountInfo, false);
if (nextAccount == null) {
alarmMgr.cancel(pi);
...
} else {
alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextCheckTime, pi);
...
}
}
}
/**
* Return a pending intent for use by this alarm. Most of the fields must be the same
* (in order for the intent to be recognized by the alarm manager) but the extras can
* be different, and are passed in here as parameters.
*/
private PendingIntent createAlarmIntent(long checkId, long[] accountInfo, boolean isWatchdog) {
Intent i = new Intent();
i.setClass(this, MailService.class);
i.setAction(ACTION_CHECK_MAIL);
i.putExtra(EXTRA_ACCOUNT, checkId);
i.putExtra(EXTRA_ACCOUNT_INFO, accountInfo);
if (isWatchdog) {
i.putExtra(EXTRA_DEBUG_WATCHDOG, true);
}
PendingIntent pi = PendingIntent.getService(this, 0, i, PendingIntent.FLAG_UPDATE_CURRENT);
return pi;
}