android - 前台服务在奥利奥上被杀死
问题描述
我正在为我的前台服务而苦苦挣扎。在我的设备(Redmi 5 Plus,Android 8.1.0)上,当从最近的应用程序中删除应用程序时,服务通知不再可见。在其他设备(Android 5.0.1、Android 7.0)和模拟器(android 8.1 - api 27)上,当从最近的应用程序中删除应用程序时,通知仍然可见。
从主要活动开始,我正在使用ContextCompat.startForegroundService(this, intent)
它来启动我的服务。
下面是前台服务的代码:
package com.ngallazzi.bluetoothtests.services
import android.annotation.SuppressLint
import android.annotation.TargetApi
import android.app.*
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.IBinder
import android.support.v4.app.NotificationCompat
import android.support.v4.app.NotificationCompat.PRIORITY_LOW
import android.util.Log
import com.ngallazzi.blemanager.managers.DeviceScanningListener
import com.ngallazzi.blemanager.managers.InRangeDetectionManager
import com.ngallazzi.bluetoothtests.MainActivity
import com.polidea.rxandroidble2.RxBleDevice
/**
* BluetoothTests
* Created by Nicola on 12/17/2018.
* Copyright © 2018 Zehus. All rights reserved.
*/
class DeviceDetectionService : Service() {
private lateinit var detectionManager: InRangeDetectionManager
override fun onBind(intent: Intent): IBinder? {
// We don't provide binding, so return null
return null
}
override fun onCreate() {
super.onCreate()
detectionManager = InRangeDetectionManager(this)
}
@SuppressLint("MissingPermission")
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if (intent != null) {
val action = intent.action
when (action) {
ACTION_START_FOREGROUND_SERVICE -> {
startForegroundService()
detectionManager.startDeviceScanning(object : DeviceScanningListener {
@SuppressLint("CheckResult")
override fun onDeviceFound(device: RxBleDevice) {
device.establishConnection(false).subscribe({
Log.v(TAG, "Connected")
displayNotification(getNotification("Connected with: {${device.name}}"))
}, {
displayNotification(getNotification("An error occurred: {$it.message!!}"))
})
}
override fun onError(message: String?) {
displayNotification(getNotification("An error occurred: {$message}"))
}
})
}
ACTION_STOP_FOREGROUND_SERVICE -> {
stopForegroundService()
}
}
}
return START_NOT_STICKY
}
@SuppressLint("MissingPermission")
private fun startForegroundService() {
startForeground(NOTIFICATION_ID, getNotification(SEARCHING_DEVICES_MESSAGE))
Log.v(TAG, "Device detection service started")
}
private fun getNotification(message: String): Notification {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
createChannel()
val mBuilder = NotificationCompat.Builder(this, CHANNEL_NAME).apply {
setSmallIcon(android.R.drawable.ic_menu_mylocation)
setContentTitle(message)
setContentIntent(getMainActivityPendingIntent())
}
return mBuilder
.setPriority(PRIORITY_LOW)
.setCategory(Notification.CATEGORY_SERVICE)
.build()
}
private fun displayNotification(notification: Notification) {
val mNotificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
mNotificationManager.notify(NOTIFICATION_ID, notification)
}
private fun getMainActivityPendingIntent(): PendingIntent {
// Create an Intent for the activity you want to start
val intent = Intent(this, MainActivity::class.java)
// Create the TaskStackBuilder
val pendingIntent = PendingIntent.getActivity(
this, 0,
intent, PendingIntent.FLAG_UPDATE_CURRENT
);
return pendingIntent!!
}
@TargetApi(26)
@Synchronized
private fun createChannel() {
val mNotificationManager = this.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val importance = NotificationManager.IMPORTANCE_DEFAULT
val mChannel = NotificationChannel(CHANNEL_NAME, SEARCHING_DEVICES_MESSAGE, importance)
mNotificationManager.createNotificationChannel(mChannel)
}
private fun stopForegroundService() {
Log.d(TAG, "Stop foreground service.")
// Stop foreground service and remove the notification.
stopForeground(true)
// Stop the foreground service.
stopSelf()
}
override fun onDestroy() {
super.onDestroy()
}
companion object {
private val TAG = DeviceDetectionService::class.java.simpleName
const val NOTIFICATION_ID = 1
const val ACTION_START_FOREGROUND_SERVICE = "start_service"
const val ACTION_STOP_FOREGROUND_SERVICE = "stop_service"
const val CHANNEL_NAME = "DEVICE_DETECTION_SERVICE"
const val SEARCHING_DEVICES_MESSAGE = "Searching in range device"
}
}
这是我的清单文件:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ngallazzi.bluetoothtests">
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:allowBackup="true"
android:name=".App"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity" android:launchMode="singleInstance">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<service android:name=".services.DeviceDetectionService" android:enabled="true"/>
<receiver android:name=".BootCompletedReceiver" android:enabled="true" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.REBOOT"/>
<action android:name="android.intent.action.QUICKBOOT_POWERON"/>
</intent-filter>
</receiver>
</application>
</manifest>
我错过了什么?它是否与后台执行限制有关?
解决方案
尝试这个
步骤 1 ) 在android:process="classname" 清单文件
android:process
中的服务类标签中 添加此标签
然后在服务类中执行此操作
步骤 2
onTaskRemoved()
)在服务类中覆盖使用警报管理器重新启动服务
步骤 3 ) 要求用户启用具有自定义操作系统的自动运行 权限
如果用户启用它,那么您的服务将在应用程序被杀死后运行。
注意:- 复制这段代码并粘贴,Kotlin 转换器会自动转换
推荐阅读
- c - 我一直在尝试使用 VSCODE 编写 c 代码,但无法正常工作
- python - standard_init_linux.go:219: exec 用户进程导致:exec 格式错误
- list - 从 Ocaml 中的列表列表中删除重复项?
- azure-devops - Azure Devops:代理在不同的构建中跳跃
- javascript - 如何在 Node.js 中重写对象或类的默认表示?(就像 Python 的 __str__ 和 __repr__ 一样)
- python - 在 Tensorflow 中使用 AUTOTUNE 时出现属性错误?
- python - 理解调用的实现
- javascript - 如何在 O(n) 时间内循环使用包含数组的对象的数组?
- c++ - OpenGL/GLSL 4.5 - 在默认 FBO 中使用 MRT
- ruby - 通过 HTTPS 代理进行 HTTPS 请求的法拉第代码