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条通知,然后自动取消不再重复,还有更多的扩展用法就自己摸索啦!本文只是简单的使用一下~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/44091.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于Three.js的WebXR渲染入门

1、Three.js 渲染管线快速概览 我不会花太多时间讨论 Three.JS 渲染管道的工作原理,因为它在互联网上有详细记录(例如,此链接)。 我将在下图中列出基础知识,以便更容易理解各个部分的去向。 2、WebXR 设备 API 入门 在我们深入了解 WebXR API 本身之前,您应该知道 WebX…

【数据结构OJ题】设计循环队列

原题链接&#xff1a;https://leetcode.cn/problems/design-circular-queue/ 1. 题目描述 2. 循环队列的概念和结构 为充分利用向量空间&#xff0c;克服"假溢出"现象的方法是&#xff1a;将向量空间想象为一个首尾相接的圆环&#xff0c;并称这种向量为循环向量。…

redis十种数据类型及底层原理

概述 Redis 是一个开源的高性能键值数据库&#xff0c;它支持多种数据类型&#xff0c;可以满足不同的业务需求。本文将介绍 Redis 的10种数据类型&#xff0c;分别是 string&#xff08;字符串&#xff09; hash&#xff08;哈希&#xff09; list&#xff08;列表&#xf…

嵌入式设计中对于只有两种状态的变量存储设计,如何高效的对循迹小车进行偏差量化

前言 &#xff08;1&#xff09;在嵌入式程序设计中&#xff0c;我们常常会要对各类传感器进行数据存储。大多时候的传感器&#xff0c;例如红外光传感器&#xff0c;返回的数据要么是0&#xff0c;要么是1。因此&#xff0c;只需要一bit就能够存储。而很多人却常常使用char型数…

对象内存布局与对象头

对象内存布局 在Hotspot虚拟机里&#xff0c;对象在堆内存中的存储布局可以划分为三个部分&#xff1a;对象头、实例数据、对齐填充。 对象头 在64为系统中&#xff0c;Mark word 占了8个字节&#xff0c;cla ss Pointer 占了8个字节。从jdk1.8开始&#xff0c;存在指针压缩&am…

【探索Linux】—— 强大的命令行工具 P.6(调试器-gdb、项目自动化构建工具-make/Makefile)

阅读导航 前言一、什么是调试器二、详解 GDB - 调试器1.使用前提2.经常使用的命令3.使用小技巧 三、项目自动化构建工具 - make/Makefile1. make命令⭕语法⭕常用选项⭕常用操作⭕make命令的工作原理⭕make命令的优势&#xff1a; 2.Makefile文件⭕Makefile的基本结构⭕Makefil…

使用pnpm workspace管理Monorepo架构

在开发项目的过程中&#xff0c;我们需要在一个仓库中管理多个项目&#xff0c;每个项目有独立的依赖、脚手架&#xff0c;这种形式的项目结构我们称之为Monorepo&#xff0c;pnpm workspace就是管理这类项目的方案之一。 一、pnpm简介 1、pnpm概述 pnpm代表performance npm…

C++系列-引用

引用 引用的基本使用引用的起源引用的语法引用的本质引用的注意事项引用和指针 引用作为函数参数引用作为函数的返回值常量引用其它用返回值方式调用函数&#xff08;case 1&#xff09;用函数的返回值初始化引用的方式调用函数&#xff08;case 2&#xff09;用返回引用的方式…

数据库--SQL关键字的执行顺序

数据库相关链接&#xff1a; 数据库--数据类型&#xff1a;http://t.csdn.cn/RtqMD 数据库--三大范式、多表查询、函数sql&#xff1a;http://t.csdn.cn/udJSG 数据库--MySQL增删改查&#xff1a;http://t.csdn.cn/xkiti 一、一条sql语句通常包括&#xff1a; select fro…

make系列之入门

一.欢迎来到我的酒馆 在本章节介绍make工具。 目录 一.欢迎来到我的酒馆二.什么是make三.make与Makefile四.如何写Makefile 二.什么是make 你可能会遇到一些名词&#xff1a;GNU&#xff0c;Linux&#xff0c;make。它们是什么&#xff0c;又有什么样的联系&#xff1f; …

正则表达式:贪婪与非贪婪模式

正则中的三种模式&#xff0c;贪婪匹配、非贪婪匹配和独占模式。 在这 6 种元字符中&#xff0c;我们可以用 {m,n} 来表示 &#xff08;*&#xff09;&#xff08;&#xff09;&#xff08;?&#xff09; 这 3 种元字符&#xff1a; 贪婪模式&#xff0c;简单说就是尽可能进行…

安卓框架中的常见问题汇总

目录 1.安卓操作系统的组件结构图如下 2.问题汇总 1.安卓操作系统的组件结构图如下 2.问题汇总 问题1&#xff1a;安卓框架中的库和应用程序框架之间什么关系&#xff1f; 在安卓系统中&#xff0c;应用程序框架层&#xff08;Application Framework&#xff09;是核心应用程…

SpringBoot + Vue 微人事权限组管理模块 (十四)

权限组前端页面制作 权限组管理角色和菜单之间关系&#xff0c;操作员管理着用户和角色之间的关系。 英文的输入框要有个前缀&#xff0c;SpringSecurity里角色英文名需要加一个ROLE_的前缀 上代码 <div><div class"permissManaTool"><el-input pla…

Java --- 二维数组

一、二维数组的定义 public class TwoArrayTest {public static void main(String[] args) {//二维数组声明与初始化//方式1&#xff1a;静态初始化int[][] arr new int[][]{{1,2,3},{1,2,3},{1,2,3}};//方式2&#xff1a;动态初始化int[][] arr2 new int[3][3];arr2[0][1] …

vsCode使用cuda

一、vsCode使用cuda 前情提要&#xff1a;配置好mingw&#xff1a; 1.安装cuda 参考&#xff1a; **CUDA Toolkit安装教程&#xff08;Windows&#xff09;&#xff1a;**https://blog.csdn.net/qq_42951560/article/details/116131410 2.在vscode中添加includePath c_cp…

Oracle Database12c数据库官网下载和安装教程

文章目录 下载安装Oracle自带的客户端工具使用 下载 进入oracle官网 点击下载连接之后右上角会有一个下载 我们只需要数据库本体就够了 运行这个下载器 等待下好之后即可 出现 Complete 之后代表下载成功&#xff0c;然后我们解压即可 安装 双击 双击setup.exe 根据…

借助Midjourney创作龙九子图

&#xff08;本文阅读时间&#xff1a;5 分钟&#xff09; 《西游记》中有这么一段描写&#xff1a; 龙王道&#xff1a;“舍妹有九个儿子。那八个都是好的。第一个小黄龙&#xff0c;见居淮渎&#xff1b;第二个小骊龙&#xff0c;见住济渎&#xff1b;第三个青背龙&#xff0…

【C# 基础精讲】LINQ to XML查询

LINQ to XML 是 C# 中用于查询和操作 XML 数据的强大工具。它允许您使用 LINQ 查询语法对 XML 文档进行查询、过滤、投影等操作&#xff0c;从而更加方便地处理 XML 数据。本文将详细介绍 LINQ to XML 的基本概念、常见操作以及示例&#xff0c;帮助您了解如何在 C# 中使用 LIN…

Learning to Super-resolve Dynamic Scenes for Neuromorphic Spike Camera论文笔记

摘要 脉冲相机使用了“integrate and fire”机制来生成连续的脉冲流&#xff0c;以极高的时间分辨率来记录动态光照强度。但是极高的时间分辨率导致了受限的空间分辨率&#xff0c;致使重建出的图像无法很好保留原始场景的细节。为了解决这个问题&#xff0c;这篇文章提出了Sp…

生成式AI系列 —— DCGAN生成手写数字

1、模型构建 1.1 构建生成器 # 导入软件包 import torch import torch.nn as nnclass Generator(nn.Module):def __init__(self, z_dim20, image_size256):super(Generator, self).__init__()self.layer1 nn.Sequential(nn.ConvTranspose2d(z_dim, image_size * 32,kernel_s…