news 2026/4/26 17:23:28

「一文搞懂 Android Service:从入门到实战」

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
「一文搞懂 Android Service:从入门到实战」

「一文搞懂 Android Service:从入门到实战」

前言:什么是 Service?

Service 是 Android 四大组件之一,用于在后台执行长时间运行的操作。与 Thread 的区别是:Service 运行在主线程,但可以在后台执行任务,且生命周期受系统管理。

┌─────────────────────────────────────────────────────────────┐ │ Android 组件对比 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ Activity 界面组件,用户可感知 │ │ Service 后台组件,用户通常不直接感知 │ │ BroadcastReceiver 广播组件,响应系统/应用广播 │ │ ContentProvider 数据组件,提供数据共享接口 │ │ │ │ Service 与 Thread 的区别: │ │ ├── Service 生命周期受系统管理 │ │ ├── Service 可以在应用切换到后台时继续运行 │ │ ├── Service 可以绑定到多个组件 │ │ └── Thread 生命周期与创建它的组件无关 │ │ │ └─────────────────────────────────────────────────────────────┘

一、Service 三种类型

1.1 类型概览

┌─────────────────────────────────────────────────────────────┐ │ Service 三种类型 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ Started Service(启动式服务) │ │ ├── 通过 startService() 启动 │ │ ├── 独立运行,不与调用者绑定 │ │ ├── 需要手动停止(stopSelf/stopService) │ │ └── 生命周期:onCreate → onStartCommand → onDestroy │ │ │ │ Bound Service(绑定式服务) │ │ ├── 通过 bindService() 绑定 │ │ ├── 与调用者生命周期绑定 │ │ ├── 所有客户端解绑后自动销毁 │ │ └── 生命周期:onCreate → onBind → onUnbind → onDestroy │ │ │ │ Foreground Service(前台服务) │ │ ├── 必须调用 startForeground() │ │ ├── 显示持续通知,用户可见 │ │ ├── 用户主动停止才会销毁 │ │ └── 适用:音乐播放、导航、下载等 │ │ │ └─────────────────────────────────────────────────────────────┘

二、Started Service(启动式服务)

2.1 基本实现

classMyStartedService:Service(){companionobject{constvalACTION_START="com.example.service.ACTION_START"constvalACTION_STOP="com.example.service.ACTION_STOP"funstartService(context:Context){valintent=Intent(context,MyStartedService::class.java).apply{action=ACTION_START}// Android 8.0+ 需要使用 startForegroundServiceif(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){context.startForegroundService(intent)}else{context.startService(intent)}}funstopService(context:Context){valintent=Intent(context,MyStartedService::class.java)context.stopService(intent)}}overridefunonCreate(){super.onCreate()Log.d("MyService","onCreate: 服务创建")}overridefunonStartCommand(intent:Intent?,flags:Int,startId:Int):Int{Log.d("MyService","onStartCommand: startId=$startId")when(intent?.action){ACTION_START->{// 执行后台任务startBackgroundTask()}ACTION_STOP->{stopSelf()}}// 返回值说明:// START_STICKY: 服务被杀死后会自动重启(不带 Intent)// START_NOT_STICKY: 服务被杀死后不会自动重启// START_REDELIVER_INTENT: 会重新传递之前的 IntentreturnSTART_STICKY}overridefunonBind(intent:Intent?):IBinder?{returnnull// Started Service 不需要绑定}overridefunonDestroy(){super.onDestroy()Log.d("MyService","onDestroy: 服务销毁")}}

2.2 启动和停止服务

// 启动服务MyStartedService.startService(this)// 停止服务MyStartedService.stopService(this)// 在 Service 内部自己停止stopSelf()

2.3 onStartCommand 返回值详解

返回值行为
START_STICKY服务被杀死后自动重启,但 Intent 为 null
START_NOT_STICKY服务被杀死后不会自动重启
START_REDELIVER_INTENT服务被杀死后会重新传递之前的 Intent

三、Bound Service(绑定式服务)

3.1 基本实现

classMyBoundService:Service(){// Binder 对象,用于返回服务实例privatevalbinder=LocalBinder()innerclassLocalBinder:Binder(){fungetService():MyBoundService=this@MyBoundService}overridefunonBind(intent:Intent?):IBinder{Log.d("MyBoundService","onBind: ")returnbinder}// 服务提供的方法fungetData():String="服务返回的数据"funexecuteTask(taskName:String):String{return"任务 [$taskName] 执行完成"}}

3.2 绑定和解绑

classMyActivity:AppCompatActivity(){privatevarmyService:MyBoundService?=nullprivatevarisBound=falseprivatevalserviceConnection=object:ServiceConnection{overridefunonServiceConnected(name:ComponentName?,service:IBinder?){valbinder=serviceasMyBoundService.LocalBinder myService=binder.getService()isBound=trueLog.d("MyActivity","服务已连接")}overridefunonServiceDisconnected(name:ComponentName?){myService=nullisBound=falseLog.d("MyActivity","服务已断开")}}overridefunonStart(){super.onStart()// 绑定服务Intent(this,MyBoundService::class.java).also{intent->bindService(intent,serviceConnection,Context.BIND_AUTO_CREATE)}}overridefunonStop(){super.onStop()// 解绑服务if(isBound){unbindService(serviceConnection)isBound=false}}funonCallServiceMethod(){if(isBound&&myService!=null){valresult=myService!!.executeTask("测试任务")Log.d("MyActivity",result)}}}

3.3 ServiceConnection 回调

回调触发时机
onServiceConnected服务成功绑定时调用
onServiceDisconnected服务意外断开连接时调用(如被系统杀死)

四、Foreground Service(前台服务)

4.1 基本实现

classMyForegroundService:Service(){companionobject{constvalCHANNEL_ID="foreground_service_channel"constvalNOTIFICATION_ID=1funstartService(context:Context){valintent=Intent(context,MyForegroundService::class.java)if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){context.startForegroundService(intent)}else{context.startService(intent)}}funstopService(context:Context){context.stopService(Intent(context,MyForegroundService::class.java))}}overridefunonCreate(){super.onCreate()createNotificationChannel()}overridefunonStartCommand(intent:Intent?,flags:Int,startId:Int):Int{// 启动前台服务(必须)startForeground(NOTIFICATION_ID,createNotification("服务运行中..."))// 开始后台任务startBackgroundTask()returnSTART_STICKY}overridefunonBind(intent:Intent?):IBinder?=nulloverridefunonDestroy(){super.onDestroy()stopForeground(STOP_FOREGROUND_REMOVE)}privatefuncreateNotificationChannel(){if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){valchannel=NotificationChannel(CHANNEL_ID,"前台服务通知",NotificationManager.IMPORTANCE_LOW).apply{description="前台服务通知"}valnotificationManager=getSystemService(NotificationManager::class.java)notificationManager.createNotificationChannel(channel)}}privatefuncreateNotification(content:String):Notification{// 创建通知...returnNotificationCompat.Builder(this,CHANNEL_ID).setContentTitle("前台服务").setContentText(content).setSmallIcon(R.drawable.ic_notification).setOngoing(true).build()}}

4.2 前台服务通知构建

privatefuncreateNotification(content:String,isPlaying:Boolean):Notification{valintent=Intent(this,MainActivity::class.java)valpendingIntent=PendingIntent.getActivity(this,0,intent,PendingIntent.FLAG_UPDATE_CURRENTorPendingIntent.FLAG_IMMUTABLE)valstopIntent=Intent(this,MyForegroundService::class.java).apply{action=ACTION_STOP}valstopPendingIntent=PendingIntent.getService(this,1,stopIntent,PendingIntent.FLAG_UPDATE_CURRENTorPendingIntent.FLAG_IMMUTABLE)returnNotificationCompat.Builder(this,CHANNEL_ID).setContentTitle("🎵 音乐播放").setContentText(content).setSmallIcon(R.drawable.ic_notification).setContentIntent(pendingIntent).addAction(R.drawable.ic_stop,"停止",stopPendingIntent).setOngoing(true).setSilent(true).build()}

五、Service 生命周期

5.1 生命周期图

┌─────────────────────────────────────────────────────────────┐ │ Started Service 生命周期 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ startService() ──▶ onCreate() ──▶ onStartCommand() │ │ │ │ │ ▼ │ │ 服务运行中... │ │ │ │ │ ▼ │ │ stopSelf() / stopService() │ │ │ │ │ ▼ │ │ onDestroy() │ │ │ └─────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────┐ │ Bound Service 生命周期 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ bindService() ──▶ onCreate() ──▶ onBind() │ │ │ │ │ ▼ │ │ 服务运行中... │ │ │ │ │ 所有客户端 unbindService() │ │ │ │ │ ▼ │ │ onUnbind() │ │ │ │ │ ▼ │ │ onDestroy() │ │ │ └─────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────┐ │ Foreground Service 生命周期 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ startForegroundService() ──▶ onCreate() ──▶ onStartCommand│ │ │ │ │ ▼ │ │ startForeground() │ │ │ │ │ ▼ │ │ 服务持续运行... │ │ (用户可见通知) │ │ │ │ │ ▼ │ │ stopForeground() + stopSelf() │ │ │ │ │ ▼ │ │ onDestroy() │ │ │ └─────────────────────────────────────────────────────────────┘

5.2 混合使用:Started + Bound

┌─────────────────────────────────────────────────────────────┐ │ 同时使用两种绑定方式 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ startService() ──▶ onCreate() ──▶ onStartCommand() │ │ │ │ │ │ │ │ │ │ │ bindService() ──▶ onBind() │ │ │ │ │ │ │ ▼ │ │ │ 服务运行中... │ │ │ │ │ │ │ unbindService() ──▶ onUnbind() │ │ │ │ │ │ └────── stopSelf() / stopService() │ │ │ │ │ │ │ ▼ │ │ └──────────────────────────▶ onDestroy() │ │ │ └─────────────────────────────────────────────────────────────┘

六、IntentService

6.1 已废弃的 IntentService

// IntentService 已在 Android 11 (API 30) 废弃// 推荐使用 Kotlin 协程 + WorkManager// 旧的 IntentService 写法(仅供参考)@Deprecated("Use WorkManager or Kotlin Coroutines instead")classMyIntentService:IntentService("MyIntentService"){overridefunonHandleIntent(intent:Intent?){// 在子线程执行后台任务Log.d("MyIntentService","处理任务:${intent?.action}")}}

6.2 现代替代方案

// 使用 Kotlin 协程的替代方案classMyCoroutineService:Service(){privatevalscope=CoroutineScope(Dispatchers.Default+SupervisorJob())overridefunonStartCommand(intent:Intent?,flags:Int,startId:Int):Int{intent?.action?.let{action->scope.launch{// 在 Default 线程池执行processTask(action)}}returnSTART_NOT_STICKY}privatesuspendfunprocessTask(action:String){// 协程中执行后台任务delay(1000)Log.d("MyCoroutineService","任务完成:$action")}overridefunonBind(intent:Intent?):IBinder?=nulloverridefunonDestroy(){super.onDestroy()scope.cancel()}}// 或者使用 WorkManager(推荐用于后台任务)classMyWorker(context:Context,params:WorkerParameters):CoroutineWorker(context,params){overridesuspendfundoWork():Result{// 在后台线程执行Log.d("MyWorker","执行工作...")returnResult.success()}}

七、注意事项与最佳实践

7.1 内存泄漏防护

classMyBoundService:Service(){privatevalbinder=LocalBinder()// 使用 WeakReference 保存 Activity 引用privatevaractivityRef:WeakReference<Activity>?=nullfunsetActivity(activity:Activity){activityRef=WeakReference(activity)}innerclassLocalBinder:Binder(){fungetService():MyBoundService=this@MyBoundService}}

7.2 前台服务权限

<!-- Android 9 (API 28) 需要声明权限 --><uses-permissionandroid:name="android.permission.FOREGROUND_SERVICE"/><!-- Android 14 (API 34) 需要声明具体类型 --><uses-permissionandroid:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE"/>

7.3 服务保活

┌─────────────────────────────────────────────────────────────┐ │ 服务保活注意事项 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ ⚠️ Android 6.0+ 后台限制: │ │ ├── 系统会杀死后台运行过久的服务 │ │ ├── 使用前台服务确保重要任务执行 │ │ └── 可以使用 WorkManager 安排延迟任务 │ │ │ │ ⚠️ Android 8.0+ 后台限制: │ │ ├── 不能在后台启动服务(使用 startForegroundService) │ │ └── 必须在 5 秒内调用 startForeground() │ │ │ │ ⚠️ Android 12 (API 31) 限制: │ │ ├── 不能在后台启动前台服务 │ │ └── 需要用户授权 FOREGROUND_SERVICE 权限 │ │ │ │ ✅ 推荐做法: │ │ ├── 优先使用 WorkManager 处理后台任务 │ │ ├── 音乐播放等使用前台服务 + 通知 │ │ └── 考虑使用 Jetpack WorkManager 替代 IntentService │ │ │ └─────────────────────────────────────────────────────────────┘

7.4 Service 与 Activity 通信

// 方式 1: Bound Service + Binder// 见 Bound Service 示例// 方式 2: BroadcastReceiverclassMyService:Service(){privatevalreceiver=object:BroadcastReceiver(){overridefunonReceive(context:Context?,intent:Intent?){when(intent?.action){"ACTION_UPDATE"->{valprogress=intent.getIntExtra("progress",0)// 更新 UI}}}}overridefunonCreate(){super.onCreate()registerReceiver(receiver,IntentFilter("ACTION_UPDATE"))}overridefunonDestroy(){super.onDestroy()unregisterReceiver(receiver)}}// 方式 3: LocalBroadcastManager(已废弃,使用 LiveData/Flow)// 推荐使用 LiveData 或 Flow 进行 Service 与 Activity 通信

总结

┌────────────────────────────────────────────────────────────┐ │ Android Service 全景图 │ ├────────────────────────────────────────────────────────────┤ │ │ │ 三种类型: │ │ ├── Started Service - startService() 独立运行 │ │ ├── Bound Service - bindService() 生命周期绑定 │ │ └── Foreground - startForeground() 用户可见 │ │ │ │ 生命周期回调: │ │ ├── onCreate() 服务创建(只调用一次) │ │ ├── onStartCommand() 处理启动请求(可多次调用) │ │ ├── onBind() 绑定服务 │ │ ├── onUnbind() 解绑服务 │ │ └── onDestroy() 服务销毁 │ │ │ │ 返回值含义: │ │ ├── START_STICKY 被杀死 后自动重启 │ │ ├── START_NOT_STICKY 被杀死 后不重启 │ │ └── START_REDELIVER 被杀死 后重传 Intent │ │ │ │ 现代替代: │ │ ├── IntentService → WorkManager + Coroutines │ │ ├── 后台服务 → Jetpack WorkManager │ │ └── 线程处理 → Kotlin Coroutines │ │ │ │ 注意事项: │ │ ├── 前台服务需要权限和通知渠道 │ │ ├── 注意内存泄漏,使用 WeakReference │ │ ├── Android 8.0+ 后台启动服务限制 │ │ └── 优先使用现代方案(协程/WorkManager) │ │ │ └────────────────────────────────────────────────────────────┘
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/26 17:10:29

Real-ESRGAN-ncnn-vulkan终极指南:3分钟让模糊图片变高清的AI神器

Real-ESRGAN-ncnn-vulkan终极指南&#xff1a;3分钟让模糊图片变高清的AI神器 【免费下载链接】Real-ESRGAN-ncnn-vulkan NCNN implementation of Real-ESRGAN. Real-ESRGAN aims at developing Practical Algorithms for General Image Restoration. 项目地址: https://gitc…

作者头像 李华
网站建设 2026/4/26 17:04:31

3个关键步骤掌握XLeRobot强化学习训练:从零到实战的完整指南

3个关键步骤掌握XLeRobot强化学习训练&#xff1a;从零到实战的完整指南 【免费下载链接】XLeRobot XLeRobot: Practical Dual-Arm Mobile Home Robot for $660 项目地址: https://gitcode.com/GitHub_Trending/xl/XLeRobot 还在为机器人强化学习训练的高成本和复杂环境…

作者头像 李华
网站建设 2026/4/26 17:03:34

AI爬虫黑名单实战:保护网站内容不被大模型抓取的完整指南

1. 项目概述&#xff1a;为什么我们需要一个专门的AI爬虫黑名单&#xff1f; 如果你运营着一个网站&#xff0c;无论是个人博客、作品集还是商业站点&#xff0c;你可能已经习惯了在根目录放一个 robots.txt 文件&#xff0c;用来告诉搜索引擎的爬虫哪些页面可以访问&#x…

作者头像 李华