Skip to content

一、Service 的核心特性

  1. 无界面:在后台独立运行,不与用户直接交互。
  2. 生命周期可控:通过 startService()bindService() 管理。
  3. 主线程运行:默认运行在主线程,耗时操作需自行启动子线程。
  4. 优先级较高:相比普通线程,Service 更不易被系统回收。

二、Service 生命周期

1. 启动服务(Started Service)

  • 启动方式startService(intent)
  • 生命周期方法
    • onCreate():首次创建时调用。
    • onStartCommand(intent, flags, startId):每次通过 startService() 启动时调用。
    • onDestroy():服务终止时调用。
  • 终止方式stopSelf()stopService(intent)

2. 绑定服务(Bound Service)

  • 启动方式bindService(intent, connection, flags)
  • 生命周期方法
    • onCreate()
    • onBind(intent):返回 IBinder 对象供客户端交互。
    • onUnbind(intent):所有客户端解绑时调用。
    • onDestroy()
  • 终止方式:当所有客户端解绑后,系统自动销毁。

3. 混合模式

服务可同时被启动和绑定,需处理两种生命周期叠加的情况。


三、Service 类型与实现

1. 普通 Service

示例代码

kotlin
class MyService : Service() {
    override fun onBind(intent: Intent): IBinder? = null

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        // 执行后台任务(需自行启动线程)
        Thread {
            // 模拟耗时操作
            Thread.sleep(5000)
            stopSelf() // 任务完成后停止服务
        }.start()
        return START_STICKY // 服务被杀死后自动重启
    }
}

启动与停止

kotlin
// 启动服务
val intent = Intent(this, MyService::class.java)
startService(intent)

// 停止服务
stopService(intent)

2. 前台服务(Foreground Service)

  • 特点:在状态栏显示持续通知,避免被系统杀死。
  • 适配要求:Android 8.0+ 需创建通知渠道。

示例代码

kotlin
class ForegroundService : Service() {
    override fun onBind(intent: Intent): IBinder? = null

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        // 创建通知渠道(Android 8.0+)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(
                "foreground_channel",
                "前台服务",
                NotificationManager.IMPORTANCE_LOW
            )
            getSystemService(NotificationManager::class.java).createNotificationChannel(channel)
        }

        // 构建通知
        val notification = NotificationCompat.Builder(this, "foreground_channel")
            .setContentTitle("前台服务运行中")
            .setContentText("正在执行重要任务...")
            .setSmallIcon(R.drawable.ic_notification)
            .build()

        // 启动为前台服务
        startForeground(1, notification)

        return START_STICKY
    }
}

3. 绑定服务(Bound Service)

通过 IBinder 实现与客户端的交互。

示例代码

kotlin
class BoundService : Service() {
    private val binder = LocalBinder()

    inner class LocalBinder : Binder() {
        fun getService(): BoundService = this@BoundService
    }

    override fun onBind(intent: Intent): IBinder = binder

    fun performTask(data: String) {
        // 执行任务
    }
}

绑定与解绑

kotlin
class MainActivity : AppCompatActivity() {
    private var boundService: BoundService? = null
    private val connection = object : ServiceConnection {
        override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
            boundService = (service as BoundService.LocalBinder).getService()
        }

        override fun onServiceDisconnected(name: ComponentName?) {
            boundService = null
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 绑定服务
        bindService(
            Intent(this, BoundService::class.java),
            connection,
            Context.BIND_AUTO_CREATE
        )
    }

    override fun onDestroy() {
        super.onDestroy()
        // 解绑服务
        unbindService(connection)
    }
}

四、替代方案(旧版 IntentService 的替代)

1. WorkManager

  • 用途:处理延迟任务,兼容 Android 4.0+,自动适配后台限制。
  • 示例
    kotlin
    class MyWorker(appContext: Context, params: WorkerParameters) : Worker(appContext, params) {
        override fun doWork(): Result {
            // 执行后台任务
            return Result.success()
        }
    }
    
    // 调度任务
    val request = OneTimeWorkRequest.Builder(MyWorker::class.java).build()
    WorkManager.getInstance(context).enqueue(request)

2. JobIntentService(Android 8.0+)

  • 用途:替代 IntentService,兼容旧版本。
  • 示例
    kotlin
    class MyJobIntentService : JobIntentService() {
        override fun onHandleWork(intent: Intent) {
            // 执行任务
        }
    
        companion object {
            fun enqueueWork(context: Context, intent: Intent) {
                enqueueWork(
                    context,
                    MyJobIntentService::class.java,
                    1001,
                    intent
                )
            }
        }
    }

五、注意事项

  1. 主线程阻塞:Service 默认运行在主线程,需手动启动子线程执行耗时操作。
  2. 后台限制
    • Android 8.0+:限制后台服务,优先使用前台服务或 WorkManager
    • Android 10+:禁止后台启动 Activity,需用户交互触发。
  3. 服务保活:避免滥用前台服务,尊重用户隐私和系统资源。
  4. 跨进程通信:通过 MessengerAIDL 实现(需声明 <service android:process=":remote">)。

六、完整示例:音乐播放服务

kotlin
class MusicService : Service() {
    private val mediaPlayer: MediaPlayer by lazy { MediaPlayer() }

    override fun onBind(intent: Intent): IBinder? = null

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        when (intent?.action) {
            "PLAY" -> playMusic()
            "STOP" -> stopMusic()
        }
        return START_STICKY
    }

    private fun playMusic() {
        if (!mediaPlayer.isPlaying) {
            mediaPlayer.apply {
                setDataSource("/sdcard/music.mp3")
                prepare()
                start()
            }
        }
    }

    private fun stopMusic() {
        mediaPlayer.stop()
        stopSelf()
    }

    override fun onDestroy() {
        mediaPlayer.release()
        super.onDestroy()
    }
}

启动服务

kotlin
val intent = Intent(this, MusicService::class.java).apply {
    action = "PLAY"
}
startService(intent)

通过合理使用 Service,可实现高效的后台任务管理,但需遵循 Android 平台的最佳实践,确保应用性能和用户体验。