Service #
一、Service概述 #
Service是Android四大组件之一,用于在后台执行长时间运行的操作,不提供用户界面。Service可以用于播放音乐、下载文件、处理网络请求等场景。
1.1 Service的特点 #
- 运行在主线程中(需要创建子线程处理耗时操作)
- 没有用户界面
- 可以在后台长时间运行
- 可以与其他组件绑定进行通信
1.2 Service的类型 #
| 类型 | 说明 |
|---|---|
| 启动服务 | 通过startService()启动,独立运行 |
| 绑定服务 | 通过bindService()绑定,与组件生命周期绑定 |
| 前台服务 | 显示通知,用户可见,不易被系统杀死 |
1.3 Service的注册 #
xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp">
<application>
<service
android:name=".MyService"
android:exported="false" />
</application>
</manifest>
二、Service生命周期 #
2.1 生命周期图解 #
text
启动服务:
startService() -> onCreate() -> onStartCommand() -> 运行中 -> onDestroy()
绑定服务:
bindService() -> onCreate() -> onBind() -> 运行中 -> onUnbind() -> onDestroy()
启动并绑定:
startService() -> bindService() -> onCreate() -> onStartCommand() -> onBind()
-> 运行中 -> onUnbind() -> onDestroy()
2.2 生命周期方法 #
kotlin
class MyService : Service() {
override fun onCreate() {
super.onCreate()
Log.d("MyService", "onCreate: 服务创建")
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.d("MyService", "onStartCommand: 服务启动")
return START_STICKY
}
override fun onBind(intent: Intent): IBinder? {
Log.d("MyService", "onBind: 服务绑定")
return binder
}
override fun onUnbind(intent: Intent): Boolean {
Log.d("MyService", "onUnbind: 服务解绑")
return true
}
override fun onRebind(intent: Intent) {
super.onRebind(intent)
Log.d("MyService", "onRebind: 服务重新绑定")
}
override fun onDestroy() {
super.onDestroy()
Log.d("MyService", "onDestroy: 服务销毁")
}
}
2.3 onStartCommand返回值 #
| 返回值 | 说明 |
|---|---|
| START_STICKY | 服务被杀死后会重建,intent为null |
| START_NOT_STICKY | 服务被杀死后不会重建 |
| START_REDELIVER_INTENT | 服务被杀死后会重建,并重传最后一个intent |
| START_STICKY_COMPATIBILITY | START_STICKY的兼容版本 |
三、启动服务 #
3.1 创建启动服务 #
kotlin
class DownloadService : Service() {
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val url = intent?.getStringExtra("url")
// 在子线程中执行耗时操作
Thread {
downloadFile(url)
stopSelf() // 下载完成后停止服务
}.start()
return START_STICKY
}
private fun downloadFile(url: String?) {
// 下载逻辑
}
override fun onBind(intent: Intent): IBinder? = null
}
3.2 启动和停止服务 #
kotlin
class MainActivity : AppCompatActivity() {
fun startDownload(url: String) {
val intent = Intent(this, DownloadService::class.java).apply {
putExtra("url", url)
}
startService(intent)
}
fun stopDownload() {
val intent = Intent(this, DownloadService::class.java)
stopService(intent)
}
}
3.3 使用IntentService(已废弃) #
kotlin
// 推荐使用JobIntentService或WorkManager
class MyJobIntentService : JobIntentService() {
companion object {
private const val JOB_ID = 1000
fun enqueueWork(context: Context, work: Intent) {
enqueueWork(context, MyJobIntentService::class.java, JOB_ID, work)
}
}
override fun onHandleWork(intent: Intent) {
// 在后台线程执行
}
}
四、绑定服务 #
4.1 创建绑定服务 #
kotlin
class MusicService : Service() {
private val binder = MusicBinder()
private var mediaPlayer: MediaPlayer? = null
inner class MusicBinder : Binder() {
fun getService(): MusicService = this@MusicService
}
override fun onCreate() {
super.onCreate()
mediaPlayer = MediaPlayer()
}
override fun onBind(intent: Intent): IBinder {
return binder
}
fun play(url: String) {
mediaPlayer?.apply {
reset()
setDataSource(url)
prepare()
start()
}
}
fun pause() {
mediaPlayer?.pause()
}
fun stop() {
mediaPlayer?.stop()
}
fun getProgress(): Int {
return mediaPlayer?.currentPosition ?: 0
}
override fun onDestroy() {
super.onDestroy()
mediaPlayer?.release()
mediaPlayer = null
}
}
4.2 绑定和解绑服务 #
kotlin
class MainActivity : AppCompatActivity() {
private var musicService: MusicService? = null
private var isBound = false
private val connection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
val binder = service as MusicService.MusicBinder
musicService = binder.getService()
isBound = true
}
override fun onServiceDisconnected(name: ComponentName?) {
isBound = false
musicService = null
}
}
override fun onStart() {
super.onStart()
Intent(this, MusicService::class.java).also { intent ->
bindService(intent, connection, Context.BIND_AUTO_CREATE)
}
}
override fun onStop() {
super.onStop()
if (isBound) {
unbindService(connection)
isBound = false
}
}
fun playMusic(url: String) {
musicService?.play(url)
}
fun pauseMusic() {
musicService?.pause()
}
}
五、前台服务 #
5.1 创建前台服务 #
前台服务必须显示一个持续的通知,让用户知道应用正在后台执行操作。
kotlin
class ForegroundService : Service() {
companion object {
const val CHANNEL_ID = "foreground_service_channel"
const val NOTIFICATION_ID = 1001
}
override fun onCreate() {
super.onCreate()
createNotificationChannel()
}
private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
CHANNEL_ID,
"前台服务",
NotificationManager.IMPORTANCE_LOW
)
val manager = getSystemService(NotificationManager::class.java)
manager.createNotificationChannel(channel)
}
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val notification = NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("正在下载")
.setContentText("下载进度: 0%")
.setSmallIcon(R.drawable.ic_download)
.setPriority(NotificationCompat.PRIORITY_LOW)
.build()
startForeground(NOTIFICATION_ID, notification)
// 执行后台任务
Thread {
for (i in 1..100) {
Thread.sleep(1000)
updateNotification(i)
}
stopForeground(STOP_FOREGROUND_REMOVE)
stopSelf()
}.start()
return START_STICKY
}
private fun updateNotification(progress: Int) {
val notification = NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("正在下载")
.setContentText("下载进度: $progress%")
.setSmallIcon(R.drawable.ic_download)
.setProgress(100, progress, false)
.build()
val manager = NotificationManagerCompat.from(this)
manager.notify(NOTIFICATION_ID, notification)
}
override fun onBind(intent: Intent): IBinder? = null
}
5.2 启动前台服务 #
kotlin
class MainActivity : AppCompatActivity() {
fun startForegroundService() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(Intent(this, ForegroundService::class.java))
} else {
startService(Intent(this, ForegroundService::class.java))
}
}
}
5.3 添加权限 #
Android 9及以上需要添加权限:
xml
<manifest>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
</manifest>
六、Service与线程 #
6.1 Service运行在主线程 #
Service默认运行在主线程中,直接在Service中执行耗时操作会阻塞UI。
kotlin
class MyService : Service() {
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
// 错误:直接在主线程执行耗时操作
// Thread.sleep(10000)
// 正确:在子线程执行
Thread {
// 耗时操作
}.start()
return START_STICKY
}
}
6.2 使用协程 #
kotlin
class MyService : Service(), CoroutineScope {
private val job = Job()
override val coroutineContext: CoroutineContext
get() = Dispatchers.IO + job
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
launch {
// 在IO线程执行耗时操作
doWork()
}
return START_STICKY
}
private suspend fun doWork() {
delay(5000)
}
override fun onDestroy() {
super.onDestroy()
job.cancel()
}
}
七、Service最佳实践 #
7.1 使用WorkManager替代后台服务 #
对于不需要立即执行的后台任务,推荐使用WorkManager:
kotlin
class UploadWorker(context: Context, params: WorkerParameters) : Worker(context, params) {
override fun doWork(): Result {
// 执行后台任务
uploadFile()
return Result.success()
}
}
// 调度任务
val uploadWork = OneTimeWorkRequestBuilder<UploadWorker>()
.setConstraints(
Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
)
.build()
WorkManager.getInstance(context).enqueue(uploadWork)
7.2 使用Service处理需要立即执行的任务 #
kotlin
// 音乐播放、位置追踪等需要立即执行的任务
class MusicService : Service() {
// ...
}
7.3 正确处理服务生命周期 #
kotlin
class MyService : Service() {
private var isRunning = false
override fun onCreate() {
super.onCreate()
isRunning = true
}
override fun onDestroy() {
super.onDestroy()
isRunning = false
// 释放资源
}
}
八、总结 #
本章详细介绍了Service:
- Service的基本概念和类型
- Service的生命周期
- 启动服务的创建和使用
- 绑定服务的创建和使用
- 前台服务的创建和通知
- Service与线程的关系
- 最佳实践
Service是Android后台处理的核心组件,合理使用Service可以提升应用的用户体验。
最后更新:2026-03-26