Android Alarm闹钟API使用心得
前言
有什么办法可以在不打开App的时候,也能够触发一些操作呢?比如说发送通知,解决这个需求的办法有很多种选择,比如说官方推荐的WorkManager API,可以在后台执行一次性、耗时、定时的任务,但WorkManager是严格遵循电池优化策略的,也就是并不精准,虽然你可以设置为加急任务,但也还是不能满足精准时间。
所以,想要在精准时间触发通知,就只能使用Alarm了。
前置准备
理清自己需要的闹钟类型,首先选择闹钟类型:
“经过的时间”闹钟:
从设定闹钟开始计时,经过特定的时间触发的闹钟,与时区、语言无关
实时闹钟:
基于世界协调时间(UTC),一般情况下,按照现实时间触发的闹钟,但该方法会受到用户改变系统时间时受到影响。
是否唤醒CPU
选择完闹钟类型后,还需确定闹钟是否能够唤醒设备,正常情况下,关闭屏幕后一段时间,CPU就会陷入“睡眠状态”,非唤醒闹钟会等待CPU“醒来”的时候才一起触发,唤醒闹钟则会直接唤醒CPU直接触发。
实现定时不重复闹钟
我们先来测试一个定时,能够唤醒CPU,仅此一次的闹钟,来发送一条通知
如果target SDK为31以上,且没有被加入电池优化策略白名单,则还需要在manifest文件中添加精确闹钟权限,该权限会在安装时授予。
如果target SDK为33以上,发送通知需要通知权限,该权限需要在发送通知前主动向系统请求,不然发不了通知
<!--通知权限--><uses-permission android:name="android.permission.POST_NOTIFICATIONS" /><!--闹钟权限--><uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
首先先创建一个广播接收器,这个广播接收器用来执行闹钟时间到的时候,我们需要执行的逻辑代码,例如发送一条通知(通知权限的请求本文不再书写,默认视为你已获得通知权限),本文使用的广播接收器是MyAlarmReceiver,闹钟时间到的时候,会发送一条通知,标题是My notification,内容为Hello World! 加一个随机数。
import android.Manifest;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.util.Log;import androidx.core.app.ActivityCompat;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import androidx.core.content.ContextCompat;import java.util.Random;public class MyAlarmReceiver extends BroadcastReceiver {String CHANNEL_LOCATION_ID = "myAlarm";@Overridepublic void onReceive(Context context, Intent intent) {Log.e("TAG", "onReceive: NOTIFY_ALARM" );int count = new Random().nextInt(100);NotificationManager notificationManager = ContextCompat.getSystemService(context, NotificationManager.class);if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {int importance = NotificationManager.IMPORTANCE_DEFAULT;NotificationChannel channel = new NotificationChannel(CHANNEL_LOCATION_ID, CHANNEL_LOCATION_ID, importance);channel.setDescription("test");notificationManager.createNotificationChannel(channel);}//通知的普通点按操作Intent intentN = new Intent(context, MainActivity.class);PendingIntent pendingIntent = PendingIntent.getActivity(context, 202, intentN, PendingIntent.FLAG_IMMUTABLE);NotificationCompat.Builder builder = new NotificationCompat.Builder(context,CHANNEL_LOCATION_ID).setSmallIcon(R.drawable.notification_icon_blue)//发送通知必须指定一个smallIcon,背景需透明.setContentTitle("My notification").setContentText("Hello World!"+ count).setPriority(NotificationCompat.PRIORITY_DEFAULT).setContentIntent(pendingIntent);//发送通知,检查权限if (ActivityCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {return;}NotificationManagerCompat.from(context).notify(count, builder.build());}
}
当然,别忘了在AndroidManifest.xml中注册我们新增的receiver
<application>...<receiver android:name=".MyAlarmReceiver"android:exported="false"></receiver>
</application>
想要设置一个闹钟,就需要给系统的闹钟服务发送一个类似“预定”一样的意图,下面这段代码我设置在17点20分0秒的闹钟,时间到的时候,系统的闹钟服务就会发送一条广播到我们的广播接收器MyAlarmReceiver,根据接收到的广播进行对应的逻辑操作。
private AlarmManager alarmManager;private PendingIntent pendingIntent;private String packageName;...private void initAlarm(Context context){Intent intent = new Intent(context,MyAlarmReceiver.class);pendingIntent = PendingIntent.getBroadcast(context,0,intent,PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);}private void setOneAlarm(){Calendar calendar = Calendar.getInstance();calendar.set(Calendar.HOUR_OF_DAY,17);calendar.set(Calendar.MINUTE,20);calendar.set(Calendar.SECOND,0);Log.i("TAG", "notify time: "+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(calendar.getTime()));if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {Log.w("TAG", "alarm: must" );alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,calendar.getTimeInMillis(),pendingIntent);}else{Log.w("TAG", "alarm: normal" );alarmManager.setExact(AlarmManager.RTC_WAKEUP,calendar.getTimeInMillis(),pendingIntent);}}
好了,前置准备我们都做完了 ,只要触发setOneAlarm()方法就设定了一个闹钟,系统的闹钟服务会在17点20分0秒发送一条广播,触发MyAlarmReceiver类中的onReceive()方法,就能发送一条通知了。
但是
你的手机如果是三星或谷歌的pixel,以上方法就已经足够了。如果你的手机是国产定制化过的系统
例如小米的MIUI,华为,VIVO,OPPO等手机的话,我们还需要获取由定制系统接管的权限,拿小米的MIUI举例,这个权限叫做 自启动权限 没有这个权限的情况下不一定能触发这个闹钟(大部分时间都无法触发)
打开App的应用设置页面我们就能看到这个权限,其他系统也基本同理,不在应用信息中就在手机管家中
把这个自启动开关打开,再去设定闹钟,就能触发一个定时闹钟了。
实现重复闹钟且自动取消
重复闹钟的实现很简单,只需要设定闹钟的时候使用setRepeating方法,就能指定第一次闹钟的时间,以及重复的间隔。但想要自动取消该怎么办呢?
想要取消闹钟,就需要调用闹钟服务的cancel()方法,且传递一个一样的pendingIntent
其实实现方法很简单,只需要再定一个取消的闹钟就行了。
给我们的Receiver区分一下不同的闹钟做什么事,根据intent中的"enable"值来区分是发送通知还是取消闹钟。
为1的时候,就发送通知,为0的时候就取消闹钟。
import android.Manifest;
import android.app.AlarmManager;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.util.Log;import androidx.core.app.ActivityCompat;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import androidx.core.content.ContextCompat;import java.util.Random;public class MyAlarmReceiver extends BroadcastReceiver {public static final String NOTIFY_ALARM = "tdsss.myalarmnotify1.MyAlarmReceiver";public static final String CANCEL_ALARM = "tdsss.myalarmnotify1.cacelAlarm";String CHANNEL_LOCATION_ID = "myAlarm";@Overridepublic void onReceive(Context context, Intent intent) {int isEnable = intent.getIntExtra("enable",-1);Log.e("TAG", "alarm onReceive: " );switch (isEnable){case 1:Log.e("TAG", "onReceive: NOTIFY_ALARM" );int count = new Random().nextInt(100);NotificationManager notificationManager = ContextCompat.getSystemService(context, NotificationManager.class);if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {int importance = NotificationManager.IMPORTANCE_DEFAULT;NotificationChannel channel = new NotificationChannel(CHANNEL_LOCATION_ID, CHANNEL_LOCATION_ID, importance);channel.setDescription("test");notificationManager.createNotificationChannel(channel);}//通知的普通点按操作Intent intentN = new Intent(context, MainActivity.class);PendingIntent pendingIntent = PendingIntent.getActivity(context, 202, intentN, PendingIntent.FLAG_IMMUTABLE);NotificationCompat.Builder builder = new NotificationCompat.Builder(context,CHANNEL_LOCATION_ID).setSmallIcon(R.drawable.notification_icon_blue)//发送通知必须指定一个smallIcon,背景需透明.setContentTitle("My notification").setContentText("Hello World!"+ count).setPriority(NotificationCompat.PRIORITY_DEFAULT).setContentIntent(pendingIntent);//发送通知,检查权限if (ActivityCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {return;}NotificationManagerCompat.from(context).notify(count, builder.build());break;case 0:Log.e("TAG", "onReceive: CANCEL_ALARM" );Intent cancel = new Intent(context,MyAlarmReceiver.class);cancel.setAction(MyAlarmReceiver.NOTIFY_ALARM);intent.putExtra("enable",1);PendingIntent cancelPendingIntent = PendingIntent.getBroadcast(context,0,cancel,PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);alarmManager.cancel(cancelPendingIntent);break;default:Log.e("TAG", "onReceive: " );break;}}
}
private void setRepeatAlarmAndCancel(){alarmManager.cancel(pendingIntent);Calendar calendar = Calendar.getInstance();calendar.set(Calendar.HOUR_OF_DAY,17);calendar.set(Calendar.MINUTE,30);calendar.set(Calendar.SECOND,0);Log.e("TAG", "notify time: "+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(calendar.getTime()));alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,calendar.getTimeInMillis(),1000*60*1,pendingIntent);//cancel alarmCalendar cancelTime = Calendar.getInstance();cancelTime.set(Calendar.HOUR_OF_DAY,17);cancelTime.set(Calendar.MINUTE,35);cancelTime.set(Calendar.SECOND,0);Log.e("TAG", "cancel time: "+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(cancelTime.getTime()));Intent cancelIntent = new Intent(getContext(),MyAlarmReceiver.class);cancelIntent.setAction(MyAlarmReceiver.CANCEL_ALARM);cancelIntent.putExtra("enable",0);PendingIntent cancelPendingIntent = PendingIntent.getBroadcast(getContext(),2,cancelIntent,PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {Log.e("TAG", "alarm: must" );alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,cancelTime.getTimeInMillis(),cancelPendingIntent);}else{Log.e("TAG", "alarm: normal" );alarmManager.setExact(AlarmManager.RTC_WAKEUP,cancelTime.getTimeInMillis(),cancelPendingIntent);}}
设定完以后,系统就会在17点30分0秒时,发送5条通知,然后自动取消不再重复,还有更多的扩展用法就自己摸索啦!本文只是简单的使用一下~
相关文章:

Android Alarm闹钟API使用心得
前言 有什么办法可以在不打开App的时候,也能够触发一些操作呢?比如说发送通知,解决这个需求的办法有很多种选择,比如说官方推荐的WorkManager API,可以在后台执行一次性、耗时、定时的任务,但WorkManager是…...

什么是业务敏捷,如何实现业务敏捷?
点击链接了解详情 作者介绍 前言 随着越来越多行业的企业开始关注敏捷,业务敏捷(Business Agility)成为一个新的热点。毕竟大部分的行业和组织与软件无关,但是依然要实现业务上的敏捷,所以这个系列会主要谈两点&#…...

ATF(TF-A)安全通告 TFV-7 (CVE-2018-3639)
安全之安全(security)博客目录导读 ATF(TF-A)安全通告汇总 目录 一、ATF(TF-A)安全通告 TFV-7 (CVE-2018-3639) 二、静态缓解(Static mitigation) 三、动态缓解(Dynamic mitigation) 一、ATF(TF-A)安全通告 TFV-7 (CVE-2018…...
第三天课程下
1.项目目录介绍和运行流程 工程化开发模式中:这里不再直接编写模板语法,通过 App.vue 提供结构渲染 main.js文件 // 文件核心作用:导入App.vue,基于App.vue创建结构渲染index.html // 1. 导入 Vue 核心包 import Vue from vue// …...

嵌入式编译FFmpeg6.0版本并且组合x264
下载直通车:我用的是6.0版本的 1.准备编译: 2.进入ffmpeg源码目录,修改Makefile,添加编译选项: CFLAGS -fPIC 不加会报错 3.使用命令直接编译 ./configure --cross-prefix/home/xxx/bin/arm-linux-gnueabihf- --enable-cross-compile --targ…...

原子css 和 组件化css如何搭配使用
如果让你来实现下面这种页面,该怎么实现呢 原子化和css组件化方式写法,可以搭配起来使用,常用的css 原子css 比如 下面这些类似flex 布局,lstn curser-pointer 等常用的或者 具备一定规律性的padding margin 样式可以抽取为单独…...
Python 实现Selenium录屏的一种方法(图片整合成动态图)
由于UI层自动化的不稳定性,经常会遇到执行中断或用例失败的问题,以下是一些常见的措施。 1.详细的日志 2.定位出错时截图 3.Pytest的缓存机制(可以记录成功了哪些失败了哪些) 4.自动重试机制(如pytest-rerunfailures) 5.用例录像 用例录像是最直观的一…...

【设计模式——学习笔记】23种设计模式——策略模式Strategy(原理讲解+应用场景介绍+案例介绍+Java代码实现)
文章目录 案例引入传统方案实现实现分析 介绍基本介绍登场角色 案例实现案例一类图实现 案例二类图实现问答 策略模式在JDK源码中的使用总结文章说明 案例引入 有各种鸭子,比如野鸭、北京鸭、水鸭等。 鸭子有各种行为,比如走路、叫、飞行等。不同鸭子的…...

通讯商二要素Api接口验证真伪
随着互联网的普及和各种社交平台、电商平台、金融平台的发展,许多业务都需要用户进行实名认证,这也就涉及到了手机号码和姓名的验证问题。为了解决这个问题,现在有很多运营商提供的二要素API接口能够进行手机号码和姓名的验证,本文…...

React源码解析18(6)------ 实现useState
摘要 在上一篇文章中,我们已经实现了函数组件。同时可以正常通过render进行渲染。 而通过之前的文章,beginWork和completeWork也已经有了基本的架子。现在我们可以去实现useState了。 实现之前,我们要先修改一下我们的index.js文件&#x…...

MongoDB的下载和安装
一、MongoDB下载 下载地址:https://www.mongodb.com/try/download/community 二、安装 因为选择下载的是 .zip 文件,直接跳过安装,一步到位。 选择在任一磁盘创建空文件夹(不要使用中文路径),解压之后把…...

如何卖 Click to WhatsApp 广告最有效
2022年,大多数直接面向消费者的品牌都面临相同挑战—— Facebook 和 Instagram 的广告成本大幅增加。Business Insider 报导指出,2021年 Facebook 广告每次点击的平均成本(average cost per click)达到0.974美元,按年升…...

【UE4 RTS】10-RTS HUD Setup
前言 本篇博文主要制作了一个控件蓝图界面,用于显示当前的游戏时间 效果 步骤 1. 新建一个名为“Widgets”的文件夹 在该文件夹中新建一个控件蓝图,命名为“GameTime_HUD” 打开“GameTime_HUD”,添加如下控件 2. 打开玩家控制器“RTS_Pla…...
Python生成指定大小文件:txt/图片/视频/csv
如题,做测试的懂的都懂,不多解释 相比其他大佬,本脚本基于gpt编写后整理,生成的文件更真实,能够打开预览,看过其他人的生成脚本,只是一个符合大小,但是是空白或不能打开的文件。 话…...

Arcgis中影像图切片有白斑或者白点
效果 步骤 1、3dmax渲染或者其它原片 2、Arcgis中加载图片 原数据效果 3、定义投影和转换坐标系等等 我这边测试数据是EPSG:4326的坐标系 4、导出jp2(JPG2000)格式 转换后效果 5、发布服务 6、效果对比...
nlohmann json:通过[ ]运算符读取设置object/array
除了可以通过at,还可以通过[ ]运算符来读取和设置object/array #include <iostream> #include <nlohmann/json.hpp> using namespace std; using json = nlohmann::json;int main() {json data = R"({"name": "xiaoming","age&quo…...
rust学习-tokio::time
示例 use std::time::Duration; use tokio::{task, time::interval};#[tokio::main] async fn main() {let mut interval interval(Duration::from_secs(1));let handle task::spawn(async move {loop {interval.tick().await;println!("tick");}});handle.await.…...
Java 中 List 集合排序方法
方式一: 调用List接口自己的sort方法排序 public static void main(String[] args) {List<Integer> numListnew ArrayList<>();numList.add(999);numList.add(123);numList.add(456);numList.add(66);numList.add(9);Collections.sort(numList); //使…...

prometheus监控k8s服务并告警到钉钉
一、监控k8s集群 要监控k8s集群需要使用到以下服务用于收集监控的资源信息,node_exporter用于监控k8s集群节点的资源信息,kube-state-metrics用于监控k8s集群的deployment、statefulset、daemonset、pod等的状态,cadvisor用于监控k8s集群的p…...
Go和Java实现解释器模式
Go和Java实现解释器模式 下面通过一个四则运算来说明解释器模式的使用。 1、解释器模式 解释器模式提供了评估语言的语法或表达式的方式,它属于行为型模式。这种模式实现了一个表达式接口,该接口 解释一个特定的上下文。这种模式被用在 SQL 解析、符…...

龙虎榜——20250610
上证指数放量收阴线,个股多数下跌,盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型,指数短线有调整的需求,大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的:御银股份、雄帝科技 驱动…...
java_网络服务相关_gateway_nacos_feign区别联系
1. spring-cloud-starter-gateway 作用:作为微服务架构的网关,统一入口,处理所有外部请求。 核心能力: 路由转发(基于路径、服务名等)过滤器(鉴权、限流、日志、Header 处理)支持负…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互
物理引擎(Physics Engine) 物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作
一、上下文切换 即使单核CPU也可以进行多线程执行代码,CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短,所以CPU会不断地切换线程执行,从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...

华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建
华为云FlexusDeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色,华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型,能助力我们轻松驾驭 DeepSeek-V3/R1,本文中将分享如何…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...

【JavaWeb】Docker项目部署
引言 之前学习了Linux操作系统的常见命令,在Linux上安装软件,以及如何在Linux上部署一个单体项目,大多数同学都会有相同的感受,那就是麻烦。 核心体现在三点: 命令太多了,记不住 软件安装包名字复杂&…...