Android学习之定时任务
Android定时任务的实现方式
在Android开发中,定时任务主要可以通过以下两类方式实现:
-
Android系统组件
- Handler消息机制:通过Handler.postDelayed()实现延时任务,适合简单UI线程操作
- AlarmManager:系统级定时服务,通过PendingIntent唤醒应用,适合精准唤醒场景
- JobScheduler(API 21+):系统任务调度器,会智能合并任务节省电量
- WorkManager(AndroidX库):JobScheduler的兼容封装,支持API 14+
- Service+线程/HandlerThread:后台服务配合线程实现长期定时任务
-
编程语言支持
- RxJava:通过interval操作符实现周期性任务
- 协程:使用delay()和repeat()组合实现定时功能
- Timer:Java标准库中的TimerTask实现简单定时
从底层来看,这些实现方式本质上都是基于线程、线程池和延时操作的封装。
各个方式的实现细节
1. Handler实现方式
val handler = Handler(Looper.getMainLooper())
handler.postDelayed({// 要执行的代码
}, 1000) // 1秒后执行
适用场景:简单的UI线程延时操作,如按钮防抖、延迟加载等。
2. AlarmManager实现方式
val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = Intent(this, AlarmReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0)// 设置精确闹钟
alarmManager.setExact(AlarmManager.RTC_WAKEUP,System.currentTimeMillis() + 5000, // 5秒后pendingIntent
)
适用场景:需要精确唤醒设备的任务,如闹钟应用、定时提醒等。
3. JobScheduler实现方式
val jobScheduler = getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler
val jobInfo = JobInfo.Builder(jobId, ComponentName(this, MyJobService::class.java)).setPeriodic(15 * 60 * 1000) // 15分钟间隔.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY).build()jobScheduler.schedule(jobInfo)
适用场景:需要系统智能调度的后台任务,如数据同步、定期备份等。
4. WorkManager实现方式
val constraints = Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()val periodicWorkRequest = PeriodicWorkRequestBuilder<MyWorker>(15, TimeUnit.MINUTES // 最小间隔15分钟
).setConstraints(constraints).build()WorkManager.getInstance(this).enqueue(periodicWorkRequest)
适用场景:需要兼容旧版本的后台任务,如上载日志、定期清理缓存等。
5. Service+线程实现方式
// 在Service中
private val handlerThread = HandlerThread("TimerThread").apply { start() }
private val handler = Handler(handlerThread.looper)private val runnable = object : Runnable {override fun run() {// 定时任务逻辑handler.postDelayed(this, 5000) // 每5秒执行一次}
}override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {handler.post(runnable)return START_STICKY
}
适用场景:需要长时间运行的后台定时任务,如定位追踪、音乐播放等。
6. RxJava实现方式
Observable.interval(1, TimeUnit.SECONDS).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe {// 每秒执行一次}
适用场景:需要响应式编程风格的定时任务,如倒计时、轮询等。
7. 协程实现方式
lifecycleScope.launch {while (isActive) {// 定时任务逻辑delay(1000) // 每秒执行一次}
}
适用场景:基于协程架构的定时任务,如ViewModel中的定时操作等。
8. Timer实现方式
val timer = Timer()
timer.schedule(object : TimerTask() {override fun run() {// 定时任务逻辑}
}, 0, 1000) // 立即开始,每秒执行一次
适用场景:简单的Java定时任务实现,需要注意内存泄漏问题。
各个实现存在的问题
1. Handler实现方式
- 内存泄漏风险:
非静态内部类的Runnable
会隐式持有外部类(如Activity
)引用,若未在onDestroy()
中调用handler.removeCallbacks()
,可能导致 Activity 无法回收。// 错误示例:匿名内部类持有 Activity 引用 handler.postDelayed({ /* ... */ }, 1000)
- 线程阻塞问题:
若任务执行时间过长(如网络请求),会阻塞主线程,导致 UI 卡顿。 - 精度不稳定:
延迟时间受线程繁忙程度影响,若主线程被其他任务占用,可能导致定时不准确。
2. AlarmManager实现方式
- 精度降低(Android 4.4+):
系统会合并相近闹钟以优化电量,set()
方法变为不精确,需使用setExact()
或setExactAndAllowWhileIdle()
(适配 Android 版本)。 - 后台启动限制(Android 8.0+):
无法通过AlarmManager
直接启动后台Service
,需改用startForegroundService()
并在 5 秒内调用startForeground()
。 - 耗电明显:
使用RTC_WAKEUP
唤醒设备会频繁激活 CPU 和屏幕,高频使用可能导致电池续航骤降。
3. JobScheduler实现方式
- API 版本限制:
仅支持 Android 5.0(API 21)及以上,无法兼容低版本系统。 - 任务合并导致延迟:
系统会根据网络、充电状态等条件合并任务,无法保证即时执行。 - 无持久化能力:
设备重启后未执行的任务会丢失,需手动重新注册。
4. WorkManager实现方式
- 最小周期限制:
周期性任务的最小间隔为 15 分钟(由系统限制),无法设置更短周期。// 实际生效的最小间隔为 15 分钟,而非 5 分钟 PeriodicWorkRequestBuilder<MyWorker>(5, TimeUnit.MINUTES).build()
- 不适合即时任务:
设计用于非紧急后台任务,无法保证精确触发时间(如秒杀倒计时)。 - 调试复杂度高:
任务调度受系统策略影响较大,需结合WorkManager.getInstance().getWorkInfosByTag()
等方法调试。
5. Service+线程实现方式
- 服务被系统回收:
后台服务可能被 Android 系统强制终止(如低内存场景),需使用startForeground()
将服务设为前台状态。 - 线程管理成本高:
手动创建线程需处理线程同步、异常捕获等问题,易引发死锁或资源泄漏。 - 兼容性问题:
HandlerThread
在旧版本系统中可能存在线程调度不稳定的问题。
6. RxJava实现方式
- 内存泄漏风险:
未正确取消Disposable
会导致订阅链无法释放,需在onDestroy()
中调用dispose()
。// 错误示例:未取消订阅 observable.subscribe()// 正确示例:在生命周期结束时取消 compositeDisposable.add(observable.subscribe()) override fun onDestroy() { compositeDisposable.clear() }
- 依赖复杂度高:
需引入rxjava
和rxandroid
库,增加 APK 体积,对轻量级项目不友好。 - 背压处理缺失:
高频发射数据时若未使用Flowable
处理背压,可能导致 OOM。
7. 协程实现方式
- 协程作用域泄漏:
使用GlobalScope
启动协程可能导致内存泄漏,推荐使用lifecycleScope
或自定义CoroutineScope
。// 错误示例:使用 GlobalScope 且未取消 GlobalScope.launch { /* ... */ }// 正确示例:绑定 Activity 生命周期 lifecycleScope.launch { /* ... */ }
- 挂起函数阻塞风险:
在非阻塞上下文中错误使用阻塞操作(如Thread.sleep()
),可能导致协程调度器性能下降。 - 冷启动耗时:
首次使用协程时需初始化调度器,可能对启动速度有轻微影响。
8. Timer实现方式
- 单线程阻塞问题:
所有TimerTask
共享一个后台线程,若某个任务执行耗时,会阻塞后续任务。// 任务1耗时5秒,任务2需等待5秒后执行 timer.schedule(task1, 0); timer.schedule(task2, 1000);
- 异常处理缺陷:
若TimerTask
抛出未捕获异常,整个Timer
会终止,后续任务无法执行。 - 已被弃用趋势:
Java 官方推荐使用ScheduledExecutorService
替代,其线程池设计更灵活可靠。
总结与避坑指南
- UI 相关定时:优先用
Handler
,但需注意Runnable
的静态内部类封装和生命周期清理。 - 后台长周期任务:首选
WorkManager
,自动处理版本兼容和电量优化,避免直接使用AlarmManager
或JobScheduler
。 - 响应式编程场景:使用
RxJava
或协程,前者适合复杂异步流,后者语法更简洁且轻量。 - 避免高频唤醒:尽量将多个定时任务合并为
WorkManager
的批量调度,减少设备唤醒次数。 - 内存管理核心原则:任何持有上下文或 UI 组件引用的定时任务,必须在生命周期结束时(如
onDestroy()
)停止或取消。
相关文章:
Android学习之定时任务
Android定时任务的实现方式 在Android开发中,定时任务主要可以通过以下两类方式实现: Android系统组件 Handler消息机制:通过Handler.postDelayed()实现延时任务,适合简单UI线程操作AlarmManager:系统级定时服务&…...
WEB安全--RCE--webshell HIDS bypass4
继WEB安全--RCE--webshell HIDS bypass3的补充: 十三、时间开关 webshell: <?php ini_set("display_errors",1); function foo($test, $bar FSYSTEM) {echo $test . $bar; } $function new ReflectionFunction(foo); $q new ParseEr…...

基于python+Django+Mysql的校园二手交易市场
文章目录 基于pythonDjangoMysql的校园二手交易市场运行步骤系统设计功能设计任务目标用户特点参与者列表基本要求功能模块图 数据库设计会员用户信息表(user_userinfo)商品信息表(goods_goodsinfo)管理员用户信息表(a…...

从零打造算法题刷题助手:Agent搭建保姆级攻略
我用Trae 做了一个有意思的Agent 「大厂机试助手」。 点击 https://s.trae.com.cn/a/d2a596 立即复刻,一起来玩吧! Agent 简介 Agent名称为大厂机试助手,主要功能有以下三点。 解题: 根据用户给出的题目给出具体的解题思路引导做…...
Oracle 12c新增的数字转换验证VALIDATE_CONVERSION函数
Oracle 12c新增的数字转换验证函数 一、VALIDATE_CONVERSION函数(12c R2新增) Oracle 12c Release 2引入了原生验证函数,可直接判断字符串能否转换为指定类型: SELECT VALIDATE_CONVERSION(123.45 AS NUMBER) FROM dual; -- 返…...
参数/非参数检验和连续/离散/分类等变量类型的关系
参数统计方法通常应用于参数变量,但参数变量并不都是连续型变量。参数变量是指那些可以用参数(如均值、方差等)来描述其分布特征的变量。参数变量可以是连续型变量,也可以是离散型变量,只要它们遵循某种特定的分布&…...

懒人云电脑方案:飞牛NAS远程唤醒 + 节点小宝一键唤醒、远程控制Windows!
后台高频问题解答: “博主,飞牛NAS能定时开关机了,能不能让它顺便把家里Windows电脑也远程唤醒控制?最好点一下就能连,不用记IP端口那种!” 安排!今天这套方案完美实现: ✅ 飞牛NAS…...

【Python】第一弹:对 Python 的认知
目录 一、Python 的背景 1.1. Python 的由来 1.2 Python 的作用 1.3 Python 的优缺点 1.4 Python 的开发工具 一、Python 的背景 1.1. Python 的由来 Python 由荷兰数学和计算机科学研究学会的吉多・范罗苏姆 (Guido van Rossum)在 20 世纪 80 年代…...

直播预告 | 聚焦芯必达|打造可靠高效的国产 MCU 与智能 SBC 汽车解决方案
随着汽车电子国产化快速推进,车规级 MCU 与 CAN/LIN SBC 作为车身控制的核心组件,正面临更高的安全与可靠性挑战。品佳集团将携手芯必达微电子,深入剖析国产 MCU/SBC/智能 SBC 的最新技术与应用,助力企业打造高性能、可量产的国产…...

Java源码中有哪些细节可以参考?(持续更新)
欢迎来到啾啾的博客🐱。 记录学习点滴。分享工作思考和实用技巧,偶尔也分享一些杂谈💬。 有很多很多不足的地方,欢迎评论交流,感谢您的阅读和评论😄。 目录 String的比较final的使用transient避免序列化 St…...

GelSight Mini触觉传感器:7μm精度+3D 映射,赋能具身智能精密操作
GelSight Mini 高分辨率视触觉传感器采用先进的光学成像与触觉感知技术,赋予机器人接近人类的触觉能力。该设备可捕捉物体表面微观细节,并生成高精度的2D/3D数字映射,帮助机器人识别形状、纹理及接触力,从而执行更复杂、精准的操作…...

day 23 机器学习管道(pipeline)
在机器学习领域,“pipeline” 常被翻译为 “管道” 或 “流水线”,它是机器学习中极为重要的概念。在构建机器学习模型时,通常需按特定顺序对数据执行预处理、特征提取、模型训练以及模型评估等步骤,而使用 “pipeline” 能有效管…...
shell编程笔记
变量定义 在 Shell 中,变量定义无需声明类型,直接赋值即可。变量名区分大小写,建议使用大写字母命名环境变量,小写字母命名局部变量。赋值时等号()两边不能有空格。 MY_VAR"Hello World" # 定…...

鸿蒙仓颉开发语言实战教程:自定义组件
关于仓颉开发语言我们已经连续分享了很多天,相信大家对于仓颉开发语言已经有了一定的了解。今天我们继续进阶,分享一个仓颉开发语言中的自定义组件知识。 本文案例就以上一篇文章中的自定义tabbar为例,因为我们自己开发的tabbar一直放在inde…...

基于Spring Boot+Vue 网上书城管理系统设计与实现(源码+文档+部署讲解)
技术范围:SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容:免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论文…...

opencvsharp usb摄像头录像 c# H264编码
1.首先创建ConsoleApp,.Net 9.0,不要创建WinForm 。WInForm帧率和实际对不上,有延时。 2.下载opencvsharp。 3.下载openh264-1.8.0-win32.dll , openh264-1.8.0-win64.dll .放在根目录。 https://github.com/cisco/openh264 using OpenCv…...
ch12 课堂参考代码 及 题目参考思路
课堂参考代码 Bellman-Ford 主要思路:对所有的边进行 n-1 轮松弛操作 单源最短路算法, O ( n m ) O(nm) O(nm) using ll long long; const int maxn 5010, maxm 5010; struct Edge {int u, v, w; } E[maxm]; // d[u]: 当前 s 到 u 的最短路 ll d[m…...
uniapp 实现腾讯云 IM 消息已读回执
uniapp 实现腾讯云 IM 消息已读回执处理全攻略 一、功能实现原理 腾讯云 IM 的已读回执功能通过 消息已读上报机制 实现,核心流程如下: 接收方阅读消息时,客户端自动上报已读状态云端记录最新已读时间戳(精确到会话维度&#x…...

JavaScript 性能优化按层次逐步分析
JavaScript 性能优化实战 💡 本文数据基于Chrome 136实测验证,涵盖12项核心优化指标,通过20代码案例演示性能提升300%的实战技巧。 一、代码层深度优化 1. 高效数据操作(百万级数据处理) // 不良实践:频繁…...
三分钟打通Stable Diffusion提示词(附实战手册)
文章目录 一、提示词的本质是"思维翻译器"避坑指南1:三大常见翻车现场 二、结构化提示词公式(抄作业版)实战案例:生成赛博朋克猫咪 三、进阶玩家的秘密武器1. 权重控制大法2. 风格融合黑科技3. 时间轴控制 四、避不开的…...

【Linux网络篇】:初步理解应用层协议以及何为序列化和反序列化
✨感谢您阅读本篇文章,文章内容是个人学习笔记的整理,如果哪里有误的话还请您指正噢✨ ✨ 个人主页:余辉zmh–CSDN博客 ✨ 文章所属专栏:Linux篇–CSDN博客 文章目录 一.序列化和反序列化为什么需要序列化和反序列化为什么应用层…...
RK3588 Opencv-ffmpeg-rkmpp-rkrga编译与测试
RK3588 Opencv-ffmpeg-rkmpp-rkrga编译与测试 硬件背景说明编译环境准备1. 编译MPP(媒体处理平台)2. 编译RGA(图形加速库)3. 构建支持硬件加速的FFmpeg重要代码修改说明4. 验证安装5.FFmpeg转码测试OpenCV编译集成Python OpenCV+FFmpeg测试硬件背景说明 RK3588是瑞芯微推出…...

特伦斯 S75 电钢琴:奏响极致音乐体验的华丽乐章
在音乐爱好者增多、音乐教育普及,以及科技进步的推动下,电钢琴市场蓬勃发展。其在技术、品质和应用场景上变化巨大,高端化、个性化产品受青睐,应用场景愈发多元。在此背景下,特伦斯 S75 电钢琴以卓越性能和独特设计&am…...

硬件学习笔记--64 MCU的ARM核架构发展及特点
MCU(微控制器)的ARM核架构是当前嵌入式系统的主流选择,其基于ARM Cortex-M系列处理器内核,具有高性能、低功耗、丰富外设支持等特点。以下是ARM核MCU的主要架构及其发展: 1. ARM Cortex-M系列内核概览 ARM Cortex-M系…...
div或button一些好看实用的 CSS 样式示例
1:现代渐变按钮 .count {width: 800px;background: linear-gradient(135deg, #72EDF2 0%, #5151E5 100%);padding: 12px 24px;border-radius: 10px;box-shadow: 0 4px 15px rgba(81, 81, 229, 0.3);color: white;font-weight: bold;border: none;cursor: pointer;t…...

USB充电检测仪-2.USB充电检测仪硬件设计
本系列文章的最终目标是制作一个USB充电检测仪,支持的功能: 显示USB充电电压、电流、功率、充电量(单位WH);实现Typec口和USB-A口的相互转换(仅支持USB 2.0); 当然网上有很多卖这种…...
如何查询服务器的端口号
要查询服务器上某个服务正在使用的端口号,可以使用几个不同的工具和方法,具体方法取决于你对服务器的访问权限以及具体的操作系统。以下是一些常用的方法: 1. 在Linux系统上 1.1 使用 netstat 命令(需要管理员权限)&…...

AU6815集成音频DSP的2x25W数字型ClaSS D音频功率放大器(替代TAS5805)
1.特性 ● 输出配置 - 立体声 2.0: 2x25W (8Ω,21V,THD N 1%) - 立体声 2.0: 2x23W (6Ω, 18V,THD N 1%) ● 供电电压范围 - PVDD:4.5V-21V - DVDD: 1.8V 或者 3.3V ● 静态功耗 - 31.5mA at PVDD12V,BD - 18.5mA at PVDD12V,1SPW ● 音频性能指标 - Noise: ≤38uVrms - TH…...

DeepSeek R1开源模型的技术突破与AI产业格局的重构
引言 2025年,中国AI企业深度求索(DeepSeek)推出的开源模型DeepSeek-R1,以低成本、高性能和开放生态为核心特征,成为全球人工智能领域的技术焦点。这一模型不仅通过算法创新显著降低算力依赖,更通过开源策…...
打破认知壁垒重构科技驱动美好生活 大模型义务传播计划
这是一份从 CUDA 到 Agentic AI 的大模型算法工程师学习路线图,旨在帮助你系统地构建成为一名优秀大模型算法工程师所需的知识体系。 阶段一:基础夯实 🧱 这个阶段的目标是掌握编程、数学和机器学习的基础知识,为后续的深度学习和…...