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 解析、符…...
MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
Prompt Tuning、P-Tuning、Prefix Tuning的区别
一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...
python/java环境配置
环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...
Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...
线程与协程
1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指:像函数调用/返回一样轻量地完成任务切换。 举例说明: 当你在程序中写一个函数调用: funcA() 然后 funcA 执行完后返回&…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...
智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...
MVC 数据库
MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...
Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...
