Android AlarmManager - AlarmManager 初识、精确闹钟权限、闹钟覆盖

📅 2026/6/18 13:37:40
Android AlarmManager - AlarmManager 初识、精确闹钟权限、闹钟覆盖
一、AlarmManager 初识1、基本介绍AlarmManager 是 Android 系统提供的全局定时服务用于在指定时间触发任务从 Android 4.4API 19开始系统默认将闹钟调整为不精确的以批量处理任务、减少设备唤醒从而显著省电只有在特殊需求时才应使用精确闹钟例如闹钟应用设置闹钟前需要先确定时间基准主要如下两种类型说明ELAPSED_REALTIME系统启动后经过的时间适用于相对时间间隔的场景RTC真实世界时间适用于特定时刻触发的场景XXX_WAKEUP类型的闹钟例如RTC_WAKEUP能在设备休眠时唤醒 CPU非唤醒版本的闹钟要等到设备下次自然唤醒才能执行2、演示1ReceiverMyAlarmReceiver.javapublicclassMyAlarmReceiverextendsBroadcastReceiver{publicstaticfinalStringTAGMyAlarmReceiver.class.getSimpleName();OverridepublicvoidonReceive(Contextcontext,Intentintent){Log.i(TAG,触发了);}}AndroidManifest.xmlreceiverandroid:name.receiver.MyAlarmReceiverandroid:exportedfalse/2ActivityButtonbtnSetAlarmfindViewById(R.id.btn_set_alarm);btnSetAlarm.setOnClickListener(v-{AlarmManageralarmManager(AlarmManager)getSystemService(ALARM_SERVICE);IntentintentnewIntent(this,MyAlarmReceiver.class);PendingIntentpendingIntentPendingIntent.getBroadcast(this,0,intent,PendingIntent.FLAG_IMMUTABLE);alarmManager.set(AlarmManager.RTC_WAKEUP,System.currentTimeMillis()5*1000,pendingIntent);});二、精确闹钟权限1、基本介绍从 Android 12 开始使用精确闹钟必须声明权限否则报错从 Android 12 开始调用精确闹钟前务必使用 canScheduleExactAlarms 方法检查权限2、演示执行如下代码Android 10 正常执行Android 13 报错错误信息如下ButtonbtnSetAlarmfindViewById(R.id.btn_set_alarm);btnSetAlarm.setOnClickListener(v-{AlarmManageralarmManager(AlarmManager)getSystemService(ALARM_SERVICE);IntentintentnewIntent(this,MyAlarmReceiver.class);PendingIntentpendingIntentPendingIntent.getBroadcast(this,0,intent,PendingIntent.FLAG_IMMUTABLE);alarmManager.setExact(AlarmManager.RTC_WAKEUP,System.currentTimeMillis()5*1000,pendingIntent);});# 输出结果 FATAL EXCEPTION: main Process: com.my.alarmmanager, PID: 4754 java.lang.SecurityException: Caller com.my.alarmmanager needs to hold android.permission.SCHEDULE_EXACT_ALARM or android.permission.USE_EXACT_ALARM to set exact alarms.Android 13 执行如下代码检查权限AlarmManageralarmManager(AlarmManager)getSystemService(ALARM_SERVICE);if(Build.VERSION.SDK_INTBuild.VERSION_CODES.S){Log.i(TAG,Android 12 及以上);booleanresultalarmManager.canScheduleExactAlarms();Log.i(TAG,result: result);}else{Log.i(TAG,Android 12 以下);}# 输出结果 Android 12 及以上 result: false3、请求权限在 AndroidManifest.xml 文件中声明权限uses-permission android:nameandroid.permission.SCHEDULE_EXACT_ALARM /检查权限与引导授权publicclassMainActivityextendsAppCompatActivity{publicstaticfinalStringTAGMainActivity.class.getSimpleName();privateAlarmManageralarmManager;SuppressWarnings(all)OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);EdgeToEdge.enable(this);setContentView(R.layout.activity_main);ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main),(v,insets)-{InsetssystemBarsinsets.getInsets(WindowInsetsCompat.Type.systemBars());v.setPadding(systemBars.left,systemBars.top,systemBars.right,systemBars.bottom);returninsets;});alarmManager(AlarmManager)getSystemService(ALARM_SERVICE);if(checkExactAlarmPermission()){next();}else{ActivityResultLauncherIntentintentActivityResultLauncherregisterForActivityResult(newActivityResultContracts.StartActivityForResult(),o-{booleanresultalarmManager.canScheduleExactAlarms();if(result){next();}else{Toast.makeText(this,未获取到相关权限无法使用本功能,Toast.LENGTH_SHORT).show();finish();}});IntentintentnewIntent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM);intentActivityResultLauncher.launch(intent);}}privatebooleancheckExactAlarmPermission(){if(Build.VERSION.SDK_INTBuild.VERSION_CODES.S){Log.i(TAG,Android 12 及以上);booleanresultalarmManager.canScheduleExactAlarms();Log.i(TAG,result: result);returnresult;}else{Log.i(TAG,Android 12 以下);returntrue;}}privatevoidnext(){ButtonbtnSetAlarmfindViewById(R.id.btn_set_alarm);btnSetAlarm.setOnClickListener(v-{AlarmManageralarmManager(AlarmManager)getSystemService(ALARM_SERVICE);IntentintentnewIntent(this,MyAlarmReceiver.class);PendingIntentpendingIntentPendingIntent.getBroadcast(this,0,intent,PendingIntent.FLAG_IMMUTABLE);alarmManager.setExact(AlarmManager.RTC_WAKEUP,System.currentTimeMillis()5*1000,pendingIntent);});}}三、闹钟覆盖1、演示1ReceiverTestAlarmReceiver.javapublicclassTestAlarmReceiverextendsBroadcastReceiver{publicstaticfinalStringTAGTestAlarmReceiver.class.getSimpleName();SuppressWarnings(all)OverridepublicvoidonReceive(Contextcontext,Intentintent){LocalDateTimedateTimeLocalDateTime.now();DateTimeFormatterformatterDateTimeFormatter.ofPattern(yyyy-MM-dd HH:mm:ss);StringstrdateTime.format(formatter);Log.i(TAG,onReceive: str);Log.i(TAG,触发了);}}AndroidManifest.xmlreceiverandroid:name.receiver.TestAlarmReceiverandroid:exportedfalse/2ActivityButtonbtnSetAlarmfindViewById(R.id.btn_set_alarm);btnSetAlarm.setOnClickListener(v-{LocalDateTimedateTimeLocalDateTime.now();DateTimeFormatterformatterDateTimeFormatter.ofPattern(yyyy-MM-dd HH:mm:ss);StringstrdateTime.format(formatter);Log.i(TAG,btnSetAlarm click: str);AlarmManageralarmManager(AlarmManager)getSystemService(ALARM_SERVICE);IntentintentnewIntent(this,TestAlarmReceiver.class);PendingIntentpendingIntentPendingIntent.getBroadcast(this,0,intent,PendingIntent.FLAG_IMMUTABLE);alarmManager.set(AlarmManager.RTC_WAKEUP,System.currentTimeMillis()5000,pendingIntent);});3Test连续两次按钮输出如下内容btnSetAlarm click: 2026-06-15 10:01:53 btnSetAlarm click: 2026-06-15 10:01:56 onReceive: 2026-06-15 10:02:01 触发了2、基本介绍AlarmManager 判断两个闹钟是否为同一个任务是通过 PendingIntent 来进行匹配的两次执行时requestCode 都是 0Intent 也都是指向TestAlarmReceiver.class的因此生成的 PendingIntent 都是相同的第二次设置的闹钟会直接覆盖第一次设置的闹钟最终系统只会保留并触发第二次设置的闹钟