第10章 后台默默的劳动者,探究Service
Android 后台默默的劳动者深入探究 Service 的三种形态与最佳实践在 Android 开发中Service是实现后台任务的核心组件。它能在不依赖用户界面的情况下长期运行非常适合执行下载、音乐播放、数据同步等不需要用户交互的任务。然而许多开发者对 Service 存在误解——Service 默认运行在主线程中若直接在其中执行耗时操作将导致 ANRApplication Not Responding。因此合理使用线程与选择合适的 Service 类型至关重要。本文将结合《第一行代码》第 10 章的核心理论与Demo10实战项目全面解析普通服务、前台服务、任务服务IntentService 替代方案的实现原理、适用场景及 Kotlin 协程的最佳实践。项目目标通过一个统一入口MainActivity演示四种 Service 操作模式并展示 Kotlin 泛型实化、协变/逆变等高级特性。一、Service 基础生命周期与通信机制1.1 Service 的本质不是独立进程默认运行在应用主进程不是新线程所有代码包括onStartCommand()都在主线程执行必须手动创建子线程否则会阻塞 UI引发 ANR。✅正确做法在 Service 内部使用Thread、AsyncTask或Kotlin 协程执行耗时任务。1.2 两种启动方式方式方法特点启动式StartedstartService()/stopService()服务与调用者无关联即使 Activity 销毁服务仍可运行绑定式BoundbindService()/unbindService()服务与调用者绑定可跨进程通信IPCActivity 销毁时需解绑1.3 核心生命周期方法classMyService:Service(){overridefunonCreate(){/* 服务创建时调用仅一次 */}overridefunonStartCommand(intent:Intent?,flags:Int,startId:Int):Int{/* 每次 startService() 都会调用 */returnSTART_STICKY// 服务被杀死后自动重启}overridefunonBind(intent:Intent?):IBinder?{/* bindService() 时调用返回 Binder 对象 */returnbinder}overridefunonDestroy(){/* 服务销毁时调用 */}}关键返回值START_STICKY服务被系统杀死后会重新创建但 intent 为 nullSTART_NOT_STICKY不自动重启START_REDELIVER_INTENT重启并重传 intent适合任务型服务。二、普通服务MyService基础后台任务2.1 功能设计支持启动式和绑定式两种模式提供doSomethingInService()方法供 Activity 调用使用Kotlin 协程在 IO 线程执行后台任务。2.2 绑定通信Binder 机制// Service 内部定义 BinderinnerclassMyBinder:Binder(){fungetService():MyServicethisMyService}// Activity 中获取 Service 实例privatevalconnectionobject:ServiceConnection{overridefunonServiceConnected(name:ComponentName,service:IBinder){valbinderserviceasMyService.MyBinder myServicebinder.getService()// 获取 Service 对象myService?.doSomethingInService()// 调用方法}}✅优势无需 AIDL即可实现 Activity 与 Service 的直接方法调用。2.3 协程执行后台任务privatevarjob:Job?nulloverridefunonStartCommand(...):Int{if(jobnull||!job.isActive){jobCoroutineScope(Dispatchers.IO).launch{performBackgroundTask()// suspend 函数}}returnSTART_STICKY}privatesuspendfunperformBackgroundTask(){for(iin1..10){delay(1000)// 非阻塞延迟Log.d(TAG,进度:$i/10)}}overridefunonDestroy(){job?.cancel()// 取消协程避免内存泄漏}为什么用协程自动管理线程切换结构化并发避免回调地狱cancel()可安全终止任务。✅效果演示三、前台服务ForegroundService高优先级后台任务3.1 为什么需要前台服务普通服务在内存不足时容易被系统回收前台服务会显示持续通知提升进程优先级几乎不会被杀死适用于音乐播放、导航、文件上传等用户感知的重要任务。3.2 实现步骤创建通知渠道Android 8.0构建通知调用startForeground(notificationId, notification)。3.3 关键代码ForegroundService.ktoverridefunonCreate(){super.onCreate()createNotificationChannel()// 创建渠道}overridefunonStartCommand(intent:Intent?,flags:Int,startId:Int):Int{startForeground(NOTIFICATION_ID,createNotification())// 必须在 onStartCommand 中调用jobCoroutineScope(Dispatchers.IO).launch{performLongRunningTask()}returnSTART_STICKY}privatefuncreateNotification():Notification{returnNotificationCompat.Builder(this,CHANNEL_ID).setContentTitle(前台服务运行中).setContentText(此服务正在后台运行).setSmallIcon(android.R.drawable.ic_dialog_info).build()}3.4 权限声明Android 9.0!-- AndroidManifest.xml --uses-permissionandroid:nameandroid.permission.FOREGROUND_SERVICE/⚠️注意从 Android 9 开始使用前台服务必须声明此权限。✅效果演示四、任务服务TaskServiceIntentService 的现代化替代4.1 IntentService 的局限已在Android 11API 30被弃用基于 HandlerThread不支持协程无法处理并发请求队列式执行。4.2 自定义 TaskService 设计使用协程替代 HandlerThread支持取消旧任务、启动新任务返回START_REDELIVER_INTENT确保任务可靠性。4.3 核心实现overridefunonStartCommand(intent:Intent?,flags:Int,startId:Int):Int{valtaskNameintent?.getStringExtra(task_name)?:Default Taskjob?.cancel()// 取消上一个任务jobCoroutineScope(Dispatchers.IO).launch{performTask(taskName,startId)}returnSTART_REDELIVER_INTENT// 任务失败时重试}privatesuspendfunperformTask(taskName:String,startId:Int){try{delay(3000)// 模拟耗时操作Log.d(TAG,任务完成:$taskName)}finally{stopSelfResult(startId)// 完成后停止服务}}✅优势更简洁的异步代码更好的错误处理与资源释放符合现代 Android 开发趋势。✅效果演示五、Kotlin 高级特性泛型实化、协变与逆变除了 Service项目还展示了 Kotlin 的强大语言特性5.1 泛型实化Reified GenericsinlinefunreifiedTgetTypeName():String{returnT::class.java.simpleName// 运行时获取类型}// 使用valnamegetTypeNameString()// 返回 String✅前提函数必须是inline泛型参数加reified。5.2 协变Covariance与逆变Contravariance协变out生产者只能“输出”数据 →Producerout T逆变in消费者只能“输入”数据 →Consumerin TinterfaceProduceroutT{funproduce():T}interfaceConsumerinT{funconsume(item:T)}// 协变示例StringProducer 可赋值给 ProducerAnyvalanyProducer:ProducerAnyStringProducer()// 逆变示例AnyConsumer 可接收 StringvalstringConsumer:ConsumerStringAnyConsumer()记忆口诀“Producer out, Consumer in”POCI。六、总结如何选择合适的 Service类型适用场景是否显示通知生命周期推荐技术普通服务一般后台任务如日志上传否可被系统回收协程 START_STICKY前台服务用户感知的重要任务音乐、导航是几乎不被回收协程 startForeground()任务服务一次性、可取消的后台任务否任务完成后自动停止协程 START_REDELIVER_INTENT重要提醒不要在 Service 主线程执行耗时操作及时取消协程或线程防止内存泄漏Android 8.0 必须使用通知渠道Android 9.0 前台服务需声明权限。结语Service 是 Android 后台任务的基石但随着架构演进WorkManager用于延迟/周期性任务和前台服务用于即时高优任务已成为更推荐的选择。然而理解 Service 的底层机制仍是每一位 Android 开发者的必修课。希望本文能助你掌握 Service 的精髓写出更健壮、高效的后台代码推荐阅读《第一行代码 —— Android》第 10 章Android 官方文档 - ServicesKotlin 协程官方指南全文完

相关新闻

Android 多进程开发 - 服务端死亡回调、服务端与客户端的线程环境、oneway 关键字

Android 多进程开发 - 服务端死亡回调、服务端与客户端的线程环境、oneway 关键字

一、服务端死亡回调 在绑定服务端时,可以获取服务端时的 Binder 对象,调用 Binder 对象的 linkToDeath 方法,注册死亡回调,监听服务端时是否挂了 private IMyAidlInterface myAidlInterface; private boolean isBound false;priv…

2026/7/8 10:50:24 阅读更多 →
Vue - Vue2 与 Vue3 自定义插件

Vue - Vue2 与 Vue3 自定义插件

Vue2 与 Vue3 自定义插件实现 在 Vue2 中,插件是一个包含 install 方法的对象,接收 Vue 构造函数作为第一个参数,以及插件选项作为第二个参数 // myPlugin.js const MyPlugin {install(Vue, options) {// 1. 添加全局方法或属性Vue.myGlobal…

2026/7/8 11:34:53 阅读更多 →
一台电脑控制N台手机实现投屏群控操作,搭建引流工作室必备技能

一台电脑控制N台手机实现投屏群控操作,搭建引流工作室必备技能

前言:做过引流获客工作室的老板或同行都知道,通过单个账号引流的风险其实挺大的,一是引流的获客通道太少,引流效果大打折扣。二是随着平台规则越来越严,即使单个账号做得再成功,万一违规就全凉了。这个时候…

2026/7/3 16:25:23 阅读更多 →

最新新闻

ViGEmBus虚拟手柄驱动:Windows游戏设备兼容性的终极解决方案

ViGEmBus虚拟手柄驱动:Windows游戏设备兼容性的终极解决方案

ViGEmBus虚拟手柄驱动:Windows游戏设备兼容性的终极解决方案 【免费下载链接】ViGEmBus Windows kernel-mode driver emulating well-known USB game controllers. 项目地址: https://gitcode.com/gh_mirrors/vi/ViGEmBus ViGEmBus是一款强大的Windows内核模…

2026/7/8 11:34:46 阅读更多 →
中国大模型领跑全球调用热潮

中国大模型领跑全球调用热潮

📰 每日AI科技资讯速递 日期:2026年7月7日 | 近24小时热点精选 🤖 一、AI大模型与大模型应用 腾讯正式发布新一代AI大模型混元Hy3 7月6日,腾讯发布混元Hy3大模型,智能水平比肩更大尺寸旗舰模型,已在多个…

2026/7/8 11:28:36 阅读更多 →
STM32G474RE与TPA3138D2高保真音频系统设计指南

STM32G474RE与TPA3138D2高保真音频系统设计指南

1. 音频系统升级方案概述在嵌入式音频系统设计中,TPA3138D2与STM32G474RE的组合堪称黄金搭档。这个方案特别适合需要高保真音频输出的便携式设备、智能家居音响系统和车载音频设备。TPA3138D2作为德州仪器推出的高效D类音频放大器,能够在3.5V至14.4V的宽…

2026/7/8 11:26:31 阅读更多 →
IIM-20670工业级IMU与PIC24EP512GU810的硬件适配与运动跟踪算法

IIM-20670工业级IMU与PIC24EP512GU810的硬件适配与运动跟踪算法

1. IIM-20670运动跟踪模块的核心特性解析 IIM-20670是TDK InvenSense推出的一款工业级6轴惯性测量单元(IMU),集成了3轴加速度计和3轴陀螺仪。这款器件最突出的特点是其卓越的环境适应性——加速度计温度稳定性达到1.7g/C,零偏重复性为1mg,在-…

2026/7/8 11:26:31 阅读更多 →
TPIS1S1385红外传感器与PIC18LF46K42微控制器的智能人体检测方案

TPIS1S1385红外传感器与PIC18LF46K42微控制器的智能人体检测方案

1. 项目背景与核心需求 在智能家居和安防领域,人体存在感应和运动检测技术正经历着从简单触发到精准感知的进化。传统PIR(被动红外)传感器只能检测移动的热源,当人体静止时就会失去响应——这导致在智能照明、安防监控等场景中频繁…

2026/7/8 11:26:31 阅读更多 →
人生宏观无解问题的最小单位是什么?

人生宏观无解问题的最小单位是什么?

第一层:什么叫宏观无解问题? 很多人每天都在思考: 我以后会不会成功?人生到底有没有意义?我是不是选错路了?十年以后会怎样?AI会不会取代我?我到底适合什么?这些问题都有…

2026/7/8 11:24:30 阅读更多 →

日新闻

3大核心能力重塑《明日方舟》游戏体验:MAA自动化助手的革命性突破

3大核心能力重塑《明日方舟》游戏体验:MAA自动化助手的革命性突破

3大核心能力重塑《明日方舟》游戏体验:MAA自动化助手的革命性突破 【免费下载链接】MaaAssistantArknights 《明日方舟》小助手,全日常一键长草!| A one-click tool for the daily tasks of Arknights, supporting all clients. 项目地址: …

2026/7/8 0:00:48 阅读更多 →
MyBatis 批量操作深度优化——从 N+1 到批处理的全路径

MyBatis 批量操作深度优化——从 N+1 到批处理的全路径

MyBatis 批量操作深度优化——从 N1 到批处理的全路径 一、从"功能正确"到"性能可接受"——MyBatis 批量操作的三段式进化 MyBatis 在日常增删改查场景中几乎是无感的——实体映射直观、SQL 控制灵活。但当数据量从千级上升到十万级、百万级,许…

2026/7/8 0:00:48 阅读更多 →
工业负载控制方案:TPD2015FN与PIC18F45K22应用解析

工业负载控制方案:TPD2015FN与PIC18F45K22应用解析

1. 工业负载控制方案概述在工业自动化、电机驱动和照明控制等高需求场景中,可靠地控制电感和电阻负载是核心挑战之一。TPD2015FN作为东芝的8通道高端智能功率开关IC,配合PIC18F45K22微控制器,能够构建一套稳定、高效的负载控制系统。这套组合…

2026/7/8 0:02:48 阅读更多 →

周新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/7 14:24:45 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里,参与了关于混合后量子密码学的讨论,应付端点攻击找茬的人,还参与留言板讨论后,发现“威胁模型”对多数人仍是陌生概念,且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/7 12:34:47 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”:我理解的渗透测试到底是什么?每次看到新闻里说某个大公司的数据被“黑”了,或者某个网站被攻击导致服务瘫痪,你是不是和我一样,心里会冒出两个念头:一是“这黑客真厉害”&#x…

2026/7/7 15:59:06 阅读更多 →

月新闻