Service 是一种可在后台执行长时间运行操作而不提供界面的应用组件。服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行。
此外,组件可通过绑定到服务与之进行交互,甚至是执行进程间通信 (IPC)。例如,服务可在后台处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序进行交互。
前台服务执行一些用户能注意到的操作。例如,音频应用会使用前台服务来播放音频曲目。前台服务必须显示通知。即使用户停止与应用的交互,前台服务仍会继续运行。
首先,Service类中使用startForeground方法来设置前台服务并显示通知。
import android.app.Notification
import android.app.PendingIntent
import android.app.Service
import android.content.Intent
import android.media.MediaPlayer
import android.os.IBinder
import androidx.core.app.NotificationCompat
class AudioPlayerService : Service() {
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
startForegroundService()
return START_NOT_STICKY
}
// 当服务启动时调用此方法。
private fun startForegroundService() {
// 创建一个意图以在通知被点击时启动MainActivity。
val notificationIntent = Intent(this, MainActivity::class.java)
// 创建一个PendingIntent来包装notificationIntent。
val pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0)
// 使用NotificationCompat.Builder构建通知。
val notification = NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("音频播放器") // 设置通知的标题。
.setContentText("正在播放音频") // 设置通知的文本内容。
.setSmallIcon(R.drawable.ic_notification) // 设置通知的小图标。
.setContentIntent(pendingIntent) // 设置通知的PendingIntent。
.build()
// 使用给定的通知启动前台服务。
startForeground(NOTIFICATION_ID, notification)
}
// 当服务被销毁时调用此方法。
override fun onDestroy() {
super.onDestroy()
// 停止服务在前台运行。
stopForeground(true)
}
// 当客户端绑定到服务时调用此方法。
override fun onBind(intent: Intent): IBinder? {
return null
}
companion object {
private const val CHANNEL_ID = "audio_channel" // 通知渠道的ID。
private const val NOTIFICATION_ID = 1 // 通知的ID。
}
}
接下来,在Activity中启动Service。
import android.content.Intent
import android.os.Bundle
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val intent = Intent(this, AudioPlayerService::class.java)
startService(intent)
}
}
注意:WorkManager API提供了一种灵活的任务调度方式,在许多情况下,可以使用WorkManager,这比直接使用前台服务更可取。
后台服务执行用户不会直接注意到的操作。例如,如果应用使用某个服务来压缩其存储空间,则此服务通常是后台服务。
示例代码:
import android.app.Service
import android.content.Intent
import android.os.IBinder
class CompressionService : Service() {
override fun onBind(intent: Intent): IBinder? {
return null
}
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
// 在这里执行压缩存储空间的操作
compressStorage()
// 压缩完成后,停止服务
stopSelf()
return START_NOT_STICKY
}
private fun compressStorage() {
// 执行压缩存储空间的操作
}
}
要在应用中启动此后台服务,可以在适当的位置(例如,活动或广播接收器)中使用以下代码:
val intent = Intent(context, CompressionService::class.java)
context.startService(intent)
这将触发CompressionService的onStartCommand方法,在其中执行压缩存储空间的操作。执行完操作后,服务将调用stopSelf()方法停止自身。
注意:如果您的应用面向 API 级别 26 或更高版本,当应用本身未在前台运行时,系统会对运行后台服务施加限制。在诸如此类的大多数情况下,您的应用应改为使用WorkManager。
当应用组件通过调用 bindService() 绑定到服务时,服务即处于绑定状态。绑定服务会提供客户端-服务器接口,以便组件与服务进行交互、发送请求、接收结果,甚至是利用进程间通信 (IPC) 跨进程执行这些操作。仅当与另一个应用组件绑定时,绑定服务才会运行。多个组件可同时绑定到该服务,但全部取消绑定后,该服务即会被销毁。
一个常见的例子是音乐播放器应用程序。以下是一个简化的示例,展示了如何使用绑定服务在应用程序中播放和控制音乐。
首先,创建一个Service类,名为MusicPlayerService,用于处理音乐播放的逻辑。
import android.app.Service
import android.content.Intent
import android.media.MediaPlayer
import android.os.Binder
import android.os.IBinder
class MusicPlayerService : Service() {
private val binder = MusicPlayerBinder()
private var mediaPlayer: MediaPlayer? = null
inner class MusicPlayerBinder : Binder() {
fun getService(): MusicPlayerService = this@MusicPlayerService
}
override fun onBind(intent: Intent): IBinder {
return binder
}
fun playMusic() {
// 在这里实现播放音乐的逻辑
mediaPlayer = MediaPlayer.create(this, R.raw.my_music)
mediaPlayer?.start()
}
fun pauseMusic() {
// 在这里实现暂停音乐的逻辑
mediaPlayer?.pause()
}
fun stopMusic() {
// 在这里实现停止音乐的逻辑
mediaPlayer?.stop()
mediaPlayer?.release()
mediaPlayer = null
}
}
接下来,在你的Activity中,你可以使用ServiceConnection来绑定服务并与之交互。以下是一个示例Activity的代码:
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.Bundle
import android.os.IBinder
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
private var isServiceBound = false
private var musicPlayerService: MusicPlayerService? = null
private val connection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
val binder = service as MusicPlayerService.MusicPlayerBinder
musicPlayerService = binder.getService()
isServiceBound = true
}
override fun onServiceDisconnected(name: ComponentName?) {
isServiceBound = false
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val playButton = findViewById<Button>(R.id.play_button)
val pauseButton = findViewById<Button>(R.id.pause_button)
val stopButton = findViewById<Button>(R.id.stop_button)
playButton.setOnClickListener {
if (isServiceBound) {
musicPlayerService?.playMusic()
}
}
pauseButton.setOnClickListener {
if (isServiceBound) {
musicPlayerService?.pauseMusic()
}
}
stopButton.setOnClickListener {
if (isServiceBound) {
musicPlayerService?.stopMusic()
}
}
}
override fun onStart() {
super.onStart()
val intent = Intent(this, MusicPlayerService::class.java)
bindService(intent, connection, Context.BIND_AUTO_CREATE)
}
override fun onStop() {
super.onStop()
if (isServiceBound) {
unbindService(connection)
isServiceBound = false
}
}
}
在这个示例中,我们在Activity的onStart方法中使用bindService方法来绑定MusicPlayerService服务,并在onStop方法中使用unbindService方法来解绑服务。
Thank you for your reading, best regards!