打开音乐 App,切到后台发现音乐还在播放;跑步时开启轨迹记录,锁屏后 GPS 依然写入路线——这些“后台持续运行”的场景,都离不开 Android 的 Service,特别是从 Android 8.0 起必须配合的 前台服务。
Service 是一个不提供 UI、运行在主线程的后台组件,专门处理不需要用户交互的长期运行操作。它的生命周期比 Activity 更独立——即使 Activity 销毁,Service 也可以继续执行。
关键生命周期:onCreate() → onStartCommand() → onBind() → onDestroy()。其中 onStartCommand 的返回值决定了系统杀掉进程后 Service 的行为:START_STICKY 会自动重启,START_NOT_STICKY 则不重启。
startService() 启动,独立于启动者运行。bindService() 绑定,提供客户端-服务端通信接口(Binder)。Android 8.0 以后,系统对后台 Service 执行有严格限制:应用进入后台几分钟后,后台 Service 会被停止。前台服务通过强制显示一个 ongoing notification 告诉用户"我还在跑",从而获得持续运行权限。
class MusicPlaybackService : Service() {
override fun onCreate() {
super.onCreate()
createNotificationChannel()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val notification = buildNotification()
// 必须在 startForeground 调用后的 5 秒内执行
startForeground(NOTIFICATION_ID, notification)
// 模拟音乐播放
Log.d("MusicService", "开始播放音乐...")
return START_STICKY // 被杀后自动重启
}
private fun createNotificationChannel() {
val channel = NotificationChannel(
CHANNEL_ID,
"音乐播放",
NotificationManager.IMPORTANCE_LOW // 静默,避免声音干扰
)
val manager = getSystemService(NotificationManager::class.java)
manager.createNotificationChannel(channel)
}
private fun buildNotification(): Notification {
return NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("正在播放")
.setContentText("音乐播放中...")
.setSmallIcon(R.drawable.ic_music)
.setOngoing(true) // 不可滑动删除
.build()
}
override fun onBind(intent: Intent?): IBinder? = null
companion object {
const val CHANNEL_ID = "music_playback"
const val NOTIFICATION_ID = 1001
}
}<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
<service
android:name=".service.MusicPlaybackService"
android:foregroundServiceType="mediaPlayback"
android:exported="false" />Android 14 起,必须显式声明 foregroundServiceType,且需要在 Manifest 中声明对应类型的权限。
// 启动前台服务
val intent = Intent(context, MusicPlaybackService::class.java)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intent)
} else {
context.startService(intent)
}
// 停止服务
val intent = Intent(context, MusicPlaybackService::class.java)
context.stopService(intent)class MusicPlaybackService : Service() {
private val binder = MusicBinder()
inner class MusicBinder : Binder() {
fun getService(): MusicPlaybackService = this@MusicPlaybackService
}
override fun onBind(intent: Intent?): IBinder = binder
// 提供给客户端的方法
fun play(songId: String) { /* ... */ }
fun pause() { /* ... */ }
}Activity 中绑定:
private val serviceConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
val binder = service as MusicBinder
binder.getService().play("song_123")
}
override fun onServiceDisconnected(name: ComponentName?) {}
}
bindService(Intent(this, MusicPlaybackService::class.java), serviceConnection, Context.BIND_AUTO_CREATE)startForegroundService() 后必须在 5 秒内调用 startForeground(),否则系统直接 ANR + 杀进程。startService() 会抛 ForegroundServiceStartNotAllowedException。解决:用 WorkManager 或 AlarmManager 替代。Service 是 Android 后台任务的基石,前台服务则是 Android 8.0+ 的标配。记住三条铁律:5 秒内调 startForeground、不在主线程做重活、任务完成及时 stopSelf。掌握了这些,你的音乐、GPS、下载等场景就能稳稳跑在后台。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。