Service
概述
Service是Android四大组件之一,是一个可以在后台执行长时间运行操作而不提供用户界面的应用组件。其他应用组件可以启动服务运行在后台,即使用户切换到其他应用,服务仍然可以在后台继续运行。
生命周期
1. 标准Service生命周期
class MyService : Service() {
override fun onCreate() {
super.onCreate()
// 服务创建时调用,只调用一次
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
// 每次服务启动时调用
return START_STICKY
}
override fun onBind(intent: Intent): IBinder? {
// 绑定服务时调用
return null
}
override fun onUnbind(intent: Intent): Boolean {
// 解绑服务时调用
return super.onUnbind(intent)
}
override fun onDestroy() {
super.onDestroy()
// 服务销毁时调用
}
}2. 启动方式
-
startService:
- 服务会一直运行,直到调用stopService或自行调用stopSelf
- 生命周期:onCreate -> onStartCommand -> onDestroy
-
bindService:
- 服务随绑定的组件的生命周期变化
- 生命周期:onCreate -> onBind -> onUnbind -> onDestroy
使用场景
- 后台音乐播放
class MusicService : Service() {
private lateinit var mediaPlayer: MediaPlayer
override fun onCreate() {
super.onCreate()
mediaPlayer = MediaPlayer()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val url = intent?.getStringExtra("music_url")
url?.let {
mediaPlayer.setDataSource(it)
mediaPlayer.prepare()
mediaPlayer.start()
}
return START_STICKY
}
}- 文件下载
class DownloadService : Service() {
private val downloadScope = CoroutineScope(Dispatchers.IO)
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val url = intent?.getStringExtra("download_url")
url?.let { startDownload(it) }
return START_NOT_STICKY
}
private fun startDownload(url: String) {
downloadScope.launch {
// 执行下载逻辑
}
}
}前台Service
1. 实现方式
class ForegroundService : Service() {
override fun onCreate() {
super.onCreate()
val notification = NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("前台服务")
.setContentText("正在运行...")
.setSmallIcon(R.drawable.ic_notification)
.build()
startForeground(1, notification)
}
}2. 使用场景
- 音乐播放器
- 文件下载
- 位置追踪
- 即时通讯
IntentService
1. 特点
- 自动处理异步任务
- 任务队列串行执行
- 执行完自动停止
2. 示例代码
class MyIntentService : IntentService("MyIntentService") {
override fun onHandleIntent(intent: Intent?) {
// 在工作线程中执行耗时操作
val data = intent?.getStringExtra("data")
// 处理数据
}
}面试常见问题
1. Service和Thread的区别?
-
Service:
- Android系统组件
- 可以与Activity交互
- 有自己的生命周期
- 可以在后台长期运行
-
Thread:
- Java线程
- 执行耗时操作
- 生命周期简单
- 依赖于进程
2. Service的启动方式有哪些?
-
startService:
- 生命周期独立
- 一直运行直到停止
- 不能与启动者通信
-
bindService:
- 生命周期依赖于绑定者
- 可以与绑定者通信
- 支持多个组件绑定
3. 如何保证Service不被杀死?
-
提高优先级:
- 使用前台服务
- START_STICKY返回值
-
系统回调重启:
- onStartCommand返回值
- 服务互相唤醒
-
其他方式:
- 添加系统服务依赖
- 使用WorkManager
4. Service和IntentService的区别?
-
Service:
- 运行在主线程
- 需要手动停止
- 可以同时处理多个请求
-
IntentService:
- 运行在工作线程
- 自动停止
- 串行处理请求
最佳实践
-
选择合适的Service类型
- 前台服务:用户可感知的任务
- 后台服务:不可见的后台任务
- IntentService:串行任务处理
-
生命周期管理
- 及时停止不需要的服务
- 合理处理绑定和解绑
- 避免内存泄漏
-
性能优化
- 避免在Service中执行耗时操作
- 使用协程或线程池
- 合理使用前台服务
源码分析
1. Service启动流程
// ActivityManagerService.java
public ComponentName startService(IApplicationThread caller,
Intent service, String resolvedType, String callingPackage,
int userId) {
// 权限检查
// 启动服务
// 生命周期回调
}2. Service绑定流程
// ContextImpl.java
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
// 创建绑定请求
// 发送到ActivityManagerService
// 建立连接
}注意事项
-
ANR问题
- 避免主线程耗时操作
- 使用异步处理机制
- 合理设置超时时间
-
内存泄漏
- 解绑时释放资源
- 避免静态引用
- 使用WeakReference
-
电池优化
- 合理使用WakeLock
- 避免频繁启动服务
- 使用JobScheduler
高级特性
- 多进程Service
// AndroidManifest.xml
<service
android:name=".RemoteService"
android:process=":remote" />- AIDL通信
// IRemoteService.aidl
interface IRemoteService {
void performTask(String data);
}- JobIntentService
class MyJobIntentService : JobIntentService() {
override fun onHandleWork(intent: Intent) {
// 处理后台任务
}
companion object {
private const val JOB_ID = 1000
fun enqueueWork(context: Context, intent: Intent) {
enqueueWork(context, MyJobIntentService::class.java, JOB_ID, intent)
}
}
}