翻译 android.app.AlarmManager 类

AlarmManager详解
本文详细介绍了Android系统的AlarmManager类,该类允许开发者为应用程序设定在未来的某个时间点运行的警报。文章涵盖了警报的不同类型(如ELAPSED_REALTIME_WAKEUP和RTC_WAKEUP)、如何使用这些类型设定一次性或重复警报,以及如何取消已设定的警报。

<!-- @page { margin: 0.79in } P { margin-bottom: 0.08in } H1 { margin-bottom: 0.08in } H1.western { font-family: "Times New Roman", serif } H1.cjk { font-family: "DejaVu Sans" } H1.ctl { font-family: "Lohit Hindi" } TD P { margin-bottom: 0in } H2 { margin-bottom: 0.08in } H2.ctl { font-family: "Lohit Hindi" } TH P { margin-bottom: 0in } A:link { so-language: zxx } CODE.cjk { font-family: "DejaVu Sans", monospace } -->

public class

AlarmManager

extends Object

java.lang.Object

   ↳

android.app.AlarmManager


类概括

Class Overview

 

本类提供了许可连接系统警服务。这里允许你预定你的应用程序在未来的某个点运行。当警报响起,已经注册到系统监听的Intent自动启动目标应用程序如果这个应用没有准备运行。在设备睡眠时已经注册的警报被保存(如果在此期间响起则能够执行唤醒设备操作),但是如果设备关闭或重启则警报将被清除。

This class provides access to the system alarm services. These allow you to schedule your application to be run at some point in the future. When an alarm goes off, the Intent that had been registered for it is broadcast by the system, automatically starting the target application if it is not already running. Registered alarms are retained while the device is asleep (and can optionally wake the device up if they go off during that time), but will be cleared if it is turned off and rebooted.

 

这个警报管理只要在警报接收者的onReceive()方法中执行就可获得一个CPU唤醒锁。这将保证电话直到你结束掌握的这个广播不会休眠。一旦OnReceive()返回,这个警报管理就释放这个唤醒锁。这意味着电话在你的onReceive()方法完成后就会在一些情况下休眠。如果你的警报监听者调用Context.startService(),电话在请求服务被执行前将会休眠的情况是可能发生的。为了预防这中情况发生,你的BroadcastReceiverService将需要执行一个分开的唤醒锁策略以确保电话在服务成为可用前继续运行。

The Alarm Manager holds a CPU wake lock as long as the alarm receiver's onReceive() method is executing. This guarantees that the phone will not sleep until you have finished handling the broadcast. Once onReceive() returns, the Alarm Manager releases this wake lock. This means that the phone will in some cases sleep as soon as your onReceive() method completes. If your alarm receiver called Context.startService(), it is possible that the phone will sleep before the requested service is launched. To prevent this, your BroadcastReceiver and Service will need to implement a separate wake lock policy to ensure that the phone continues running until the service becomes available.

 

注意:这个警报管理是预期这种情况当你要运行你的应用程序代码在一个特殊的时候,即使你的应用程序不是当前运行的。进行常规定时操作(响铃,超时设定,等)这是更简单和更多更高效的用法。

Note: The Alarm Manager is intended for cases where you want to have your application code run at a specific time, even if your application is not currently running. For normal timing operations (ticks, timeouts, etc) it is easier and much more efficient to use Handler.

 

你不能直接实例这个类;要通过Context.getSystemService(Context.ALARM_SERVICE)替换,取回他

You do not instantiate this class directly; instead, retrieve it through Context.getSystemService(Context.ALARM_SERVICE).

 

Summary

Constants

int

ELAPSED_REALTIME

警报时在SystemClock.elapsedRealtime()(时间来自boot,包括休眠)

Alarm time in SystemClock.elapsedRealtime() (time since boot, including sleep).

 

int

ELAPSED_REALTIME_WAKEUP

警报时在SystemClock.elapsedRealtime()(时间来自boot,包括休眠),当警报发生将唤醒设备。

Alarm time in SystemClock.elapsedRealtime() (time since boot, including sleep), which will wake up the device when it goes off.

 

long

INTERVAL_DAY

long

INTERVAL_FIFTEEN_MINUTES

通过setInexactRepeating(int, long, long, PendingIntent)有效的不精确的重复间隔被认可

Available inexact recurrence intervals recognized by setInexactRepeating(int, long, long, PendingIntent)

long

INTERVAL_HALF_DAY

long

INTERVAL_HALF_HOUR

long

INTERVAL_HOUR

int

RTC

警报时在System.currentTimeMillis()(UTC隔开时钟)

Alarm time in System.currentTimeMillis() (wall clock time in UTC).

 

int

RTC_WAKEUP

警报时在System.currentTimeMillis()(UTC隔开时钟),当警报发生将唤醒设备。

Alarm time in System.currentTimeMillis() (wall clock time in UTC), which will wake up the device when it goes off.

Public Methods

void

cancel(PendingIntent operation)

移除任何匹配Intent的警报。

Remove any alarms with a matching Intent.

 

void

set(int type, long triggerAtTime, PendingIntent operation)

预定一个警报。

Schedule an alarm.

 

 

void

setInexactRepeating(int type, long triggerAtTime, long interval, PendingIntent operation)

设定一个重复警报带有不精确的触发时间要件;例如,一个警报是每小时重复,但不一定在每个小时的开始重复。

Schedule a repeating alarm that has inexact trigger time requirements; for example, an alarm that repeats every hour, but not necessarily at the top of every hour.

 

void

setRepeating(int type, long triggerAtTime, long interval, PendingIntent operation)

预定一个重复警报。

Schedule a repeating alarm.

 

void

setTime(long millis)

设置系统隔开时间。

Set the system wall clock time.

 

void

setTimeZone(String timeZone)

设置系统默认时区。

Set the system default time zone.

 

<think>好的,我现在需要帮助用户解决ForegroundServiceStartNotAllowedException异常,并理解当mAllowStartForeground为false时无法调用Service.startForeground()的问题。用户之前已经提问过相关问题,并得到了详细的回答,现在用户提供了新的引用信息,需要结合之前的回答和新的引用来进一步解决。 首先,我需要回顾之前的回答。之前的回答提到了Android 8.0+的后台限制、生命周期错位调用以及PendingIntent的兼容性问题,并给出了解决方案的代码示例,包括创建通知渠道、处理不同API版本的启动方式以及权限声明等。用户现在提供的引用信息来自Android 12,指出当应用在后台运行时启动前台服务会被限制,并抛出异常,具体是当mAllowStartForeground为REASON_DENIED且后台限制启用时,会触发异常。 接下来,我需要结合新的引用信息,深入分析问题。用户的问题集中在ForegroundServiceStartNotAllowedException和mAllowStartForeground为false的情况。根据引用内容,当应用处于后台时,尝试启动前台服务会被阻止,特别是当应用的目标API为Android 12或更高时。因此,核心问题在于应用在后台状态下的前台服务启动限制。 我需要考虑以下几个方面: 1. **Android 12的后台限制**:应用在后台无法启动前台服务,必须确保应用处于前台时才启动服务。需要检查应用启动服务的上下文是否在前台。 2. **mAllowStartForeground的状态**:这个参数由系统控制,当应用不符合启动前台服务的条件时会被设置为false。需要确保应用在允许的状态下调用startForeground。 3. **异常处理**:当系统抛出ForegroundServiceStartNotAllowedException时,应用需要正确处理,避免崩溃。 4. **启动时机的调整**:可能需要将启动前台服务的操作延迟到应用回到前台时,或者通过用户交互触发。 结合之前的解决方案,可能需要补充以下几点: - 确保在应用可见或处于前台时才启动服务。 - 处理后台启动的情况,例如通过启动Activity让用户回到应用,再启动服务。 - 检查目标SDK版本,适配Android 12的新限制。 - 在代码中添加异常捕获,处理可能的ForegroundServiceStartNotAllowedException。 此外,用户提供的引用中提到了CompatChanges.isChangeEnabled,这可能涉及到兼容性框架,需要确认是否启用了相关的变更,可能需要适配。 现在需要将上述分析整理成一个结构化的回答,分步骤解释原因和解决方案,并给出代码示例,同时确保符合用户之前设定的格式,包括使用中文、LaTeX格式的正确应用、引用标注等。 需要注意用户可能希望解决方案具体针对Android 12及更高版本,同时如何处理后台启动的问题。例如,当应用在后台时,如何合法地启动前台服务,或者如何调整应用逻辑以避免在后台启动。 可能还需要提到用户触发启动前台服务的情况,例如通过前台Activity的按钮点击,而不是在后台服务或广播接收器中启动。 最后,生成相关问题,帮助用户进一步理解相关知识点,如后台限制的具体情况、如何检测应用是否在前台、其他Android版本的限制差异等。</think>针对Android 12+出现的$ForegroundServiceStartNotAllowedException$异常和$mAllowStartForeground=false$问题,结合系统源码逻辑[^1],以下是深度解决方案: --- ### 一、核心限制原理 根据Android 12系统源码规则[^1]: 1. **后台启动禁令** 当应用处于后台状态(无可见Activity/无前台组件)时,若尝试通过$startForegroundService()$启动前台服务,系统将触发: $$ \text{startForegroundService()} \xrightarrow{\text{后台状态}} \text{ForegroundServiceStartNotAllowedException} $$ 2. **策略检查机制** 系统通过$mAllowStartForeground$参数判定应用当前是否拥有前台服务启动权限: ```java if (r.mAllowStartForeground == REASON_DENIED && isBgFgsRestrictionEnabled(r)) { throw new ForegroundServiceStartNotAllowedException(...); } ``` --- ### 二、强制触发场景 以下操作会导致该异常: 1. **从后台服务/BroadcastReceiver启动** ```java // 错误示例:在后台通过AlarmManager触发服务 PendingIntent.getService(context, 0, serviceIntent, 0); ``` 2. **Activity不可见时启动** 在Activity的$onPause()$后调用$startForegroundService()$[^1] 3. **跨进程后台调用** 通过其他应用在后台触发本应用的服务启动 --- ### 三、分层解决方案 #### 第一层:启动入口合法性校验 ```java // 在启动服务前添加可见性检查 if (isAppInForeground()) { Intent serviceIntent = new Intent(context, MyForegroundService.class); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { context.startForegroundService(serviceIntent); } else { context.startService(serviceIntent); } } else { // 引导用户回到前台 bringAppToForeground(); } // 检测应用是否在前台 private boolean isAppInForeground() { ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE); List<ActivityManager.RunningAppProcessInfo> processes = am.getRunningAppProcesses(); if (processes != null) { for (ActivityManager.RunningAppProcessInfo process : processes) { if (process.processName.equals(getPackageName()) && process.importance == IMPORTANCE_FOREGROUND) { return true; } } } return false; } ``` #### 第二层:服务启动异常捕获 ```java public class MyForegroundService extends Service { @Override public void onCreate() { try { startForeground(NOTIFICATION_ID, buildNotification()); } catch (ForegroundServiceStartNotAllowedException e) { // 降级为后台服务或终止操作 stopSelf(); Log.e(TAG, "Foreground service not allowed: " + e.getMessage()); } } } ``` #### 第三层:合法启动路径设计 1. **用户交互触发** 通过可见Activity的按钮点击启动服务 ```kotlin binding.startServiceButton.setOnClickListener { if (checkSelfPermission(FOREGROUND_SERVICE) == PERMISSION_GRANTED) { val intent = Intent(this, MyForegroundService::class.java) startForegroundService(intent) } } ``` 2. **前台绑定启动** 在Activity的$onResume()$中绑定服务 ```java @Override protected void onResume() { super.onResume(); bindService(new Intent(this, MyForegroundService.class), connection, BIND_AUTO_CREATE); } ``` --- ### 四、Android 12+适配要点 1. **PendingIntent标志强制要求** ```java // 必须指定FLAG_IMMUTABLE或FLAG_MUTABLE PendingIntent.getActivity( context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE ); ``` 2. **精确的前台服务型** Android 13要求声明具体服务型: ```xml <service android:name=".MyForegroundService" android:foregroundServiceType="location|camera|microphone" /> ``` --- ### 五、调试技巧 1. **检测后台启动源头** 使用$adb shell dumpsys activity processes$查看进程状态 2. **模拟后台场景测试** ```bash adb shell am broadcast -a android.intent.action.BOOT_COMPLETED ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值