在一台Android 11的设备上,写了一个服务,发现运行1分钟后服务就被杀了,服务如下:
class MyService : Service() {
private var run = false
private fun log(msg: String) = Log.i("MyService", msg)
override fun onCreate() {
super.onCreate()
log("onCreate")
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
log("onStartCommand")
if (!run) {
run = true
thread {
while (run) {
// 每秒打印一下当前时间
log("${DateFormat.format("HH:mm:ss", System.currentTimeMillis())}")
SystemClock.sleep(1000)
}
}
}
return super.onStartCommand(intent, flags, startId)
}
override fun onDestroy() {
super.onDestroy()
run = false
log("onDestroy")
}
override fun onBind(intent: Intent?): IBinder? = null
}
要解决这个问题比较简单,把目标版本调低即可,例如:targetSdk = 22
。
如果目标版本比较高,可以使用前台服务,如下:
class MyService : Service() {
companion object {
private const val CHANNEL_ID = "MyChannelID"
}
private var run = false
private fun log(msg: String) = Log.i("MyService", msg)
override fun onCreate() {
super.onCreate()
log("onCreate")
createNotificationChannel()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
log("onStartCommand")
if (!run) {
// 创建通知
val notification: Notification = NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("守护程序服务")
.setContentText("服务正在运行...")
.setSmallIcon(R.drawable.ic_stat_name)
.setSound(null) // Android 8.0以下时在通知对象中禁止通知声,Android 8.0及以上的通知渠道对象中禁止通知声音
.build()
// 启动前台服务
startForeground(1, notification)
run = true
thread {
while (run) {
log("${DateFormat.format("HH:mm:ss", System.currentTimeMillis())}")
SystemClock.sleep(1000)
}
}
}
return super.onStartCommand(intent, flags, startId)
}
override fun onDestroy() {
super.onDestroy()
run = false
log("onDestroy")
// 停止前台服务并移除通知
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
stopForeground(STOP_FOREGROUND_REMOVE)
} else {
@Suppress("DEPRECATION")
stopForeground(true)
}
}
private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannelCompat
.Builder(CHANNEL_ID, NotificationManagerCompat.IMPORTANCE_HIGH)
.setName("守护程序通知频道")
.setSound(null, null) // Android 8.0及以上的在此处可禁止通知声
.build()
val manager = NotificationManagerCompat.from(this)
manager.createNotificationChannel(channel)
}
}
override fun onBind(intent: Intent?): IBinder? = null
}
在需要的地方启动服务:
startService(Intent(this, MyService::class.java))
不需要时关闭服务:
stopService(Intent(this, MyService::class.java))
还需要声明前台服务的权限:
<!--允许前台服务,在Android9.0的时候出的权限,如果目标版本大于等于9.0,则需要添加该权限-->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
这个权限在Android 9.0的时候才出的,所以,如果目标版本低于9.0版本的话,可以不用声明前台服务权限,而且前台服务在很早的版本就已经有了,但那时不需要权限的。