Android RemoteServiceException: Context.startForegroundService() 没有调用 Service.startForeground()
Android RemoteServiceExeption: Context.startForegroundService() did not then call Service.startForeground()
我知道,关于这个错误已经有很多问题了。但是我尝试了很多解决方案,但对我没有任何帮助。我的应用程序中有一个带有计时器的通知服务,crashlytics 报告了数百次崩溃(android 8 - 12),如下所示:
ForegroundServiceDidNotStartInTimeException:
Fatal Exception: android.app.ForegroundServiceDidNotStartInTimeException
Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord{cac9d0b u0 com.malmatech.eggtimer/.NotificationUtil}
android.app.ActivityThread.throwRemoteServiceException (ActivityThread.java:2134)
android.app.ActivityThread.access00 (ActivityThread.java:309)
android.app.ActivityThread$H.handleMessage (ActivityThread.java:2363)
android.os.Handler.dispatchMessage (Handler.java:106)
android.os.Looper.loopOnce (Looper.java:226)
android.os.Looper.loop (Looper.java:313)
android.app.ActivityThread.main (ActivityThread.java:8582)
java.lang.reflect.Method.invoke (Method.java)
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:563)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1133)
和 RemoteServiceException:
Fatal Exception: android.app.RemoteServiceException
Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord{d760a21 u0 com.malmatech.eggtimer/.NotificationUtil}
android.app.ActivityThread$H.handleMessage (ActivityThread.java:2313)
android.os.Handler.dispatchMessage (Handler.java:107)
android.os.Looper.loop (Looper.java:213)
android.app.ActivityThread.main (ActivityThread.java:8178)
java.lang.reflect.Method.invoke (Method.java)
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:513)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1101)
我仔细检查了我的代码并搜索了网络,但没有找到任何东西,也从未在我自己的设备或模拟器上遇到这些异常...
通知仅在计时器为 运行 且应用程序关闭时显示。在我的 TimerActivity 的 onPause() 中,我启动服务:
if (timerState == TimerState.Running){
timer.cancel()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
MyContext.getContext().startForegroundService(Intent(this, NotificationUtil::class.java))
} else {
startService(Intent(this, NotificationUtil::class.java))
}
}
在 onResume() 中我停止了服务:
try {
MyContext.getContext().stopService(
Intent(
MyContext.getContext(),
NotificationUtil::class.java
)
)
} catch (ex: Exception) {
ex.printStackTrace()
}
这是我的服务 class,我删除了一些不相关的代码,但应该包括管理通知的所有内容。
class NotificationUtil : Service() {
override fun onBind(intent: Intent?): IBinder? {
return null
}
var eggCount = 1
private var secondsRemaining: Long = 0
private lateinit var timer: CountDownTimer
// some more, irrelevant for question
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
showNotification()
log("onStartCommand executed with startId: $startId")
if (intent != null) {
val action = intent.action
log("using an intent with action $action")
} else {
log("with a null intent. It has been probably restarted by the system.")
}
// by returning this we make sure the service is restarted if the system kills the service
return START_STICKY
}
override fun onCreate() {
super.onCreate()
//irrelevant Code - getting an array from SharedPreferences and setting up textToSpeech
showNotification()
startTimer()
}
override fun onDestroy() {
super.onDestroy()
hideNotification()
timer.cancel()
}
fun showNotification(done: Boolean = false) {
val nBuilder = NotificationCompat.Builder(applicationContext, "menu_timer")
.setSmallIcon(R.drawable.ic_notification_res_specific)
.setOngoing(true)
.setAutoCancel(true)
.setDefaults(0)
.setContentIntent(
getPendingIntentWithStack(
applicationContext,
TimerActivity::class.java
)
)
.setPriority(PRIORITY_MAX)
.setVisibility(VISIBILITY_PUBLIC)
.setNotificationSilent()
if (!done) {
//irrelecantCode, setting ginishedStr and finishedIndividualString
nBuilder.setContentTitle(getString(R.string.eggTimerRunning))
if (eggCount > 1) {
nBuilder.setStyle(
NotificationCompat.BigTextStyle().bigText(
getString(R.string.remainingTimeNotification) + " $finishedStr\n" + getString(
R.string.nextEggNotification
) + " $finishedIndividualString"
)
)
.setContentText(
getString(R.string.remainingTimeNotification) + " $finishedStr\n" + getString(
R.string.nextEggNotification
) + " $finishedIndividualString"
)
} else {
nBuilder.setStyle(
NotificationCompat.BigTextStyle()
.bigText(getString(R.string.remainingTimeNotification) + " $finishedStr")
)
.setContentText(getString(R.string.remainingTimeNotification) + " $finishedStr")
}
} else {
nBuilder.setContentTitle(getString(R.string.eggTimerDone))
.setStyle(
NotificationCompat.BigTextStyle().bigText(getString(R.string.BonAppetite))
)
.setContentText(getString(R.string.BonAppetite))
}
//irrelevant code
val nManager =
applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
nManager.createNotificationChannel("menu_timer", "Timer App Timer", true)
nManager.notify(135678, nBuilder.build())
val notification: Notification = nBuilder.build()
startForeground(135678, notification)
}
private fun hideNotification() {
val nManager =
applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
nManager.cancel(135678)
}
private fun startTimer() {
timer = object : CountDownTimer(secondsRemaining * 1000, 1000) {
override fun onFinish() = onTimerFinished()
override fun onTick(millisUntilFinished: Long) {
secondsRemaining = millisUntilFinished / 1000
showNotification()
}
}.start()
}
private fun onTimerFinished(ring: Boolean = true) {
if (ring) {
//irrelevant code, ring and vibrate if timer is finished
}
showNotification(true)
}
@TargetApi(26)
private fun NotificationManager.createNotificationChannel(
channelID: String,
channelName: String,
playSound: Boolean
) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channelImportance = if (playSound) NotificationManager.IMPORTANCE_DEFAULT
else NotificationManager.IMPORTANCE_LOW
val nChannel = NotificationChannel(channelID, channelName, channelImportance)
nChannel.enableLights(true)
nChannel.lightColor = Color.BLUE
this.createNotificationChannel(nChannel)
}
}
private fun <T> getPendingIntentWithStack(
context: Context,
javaClass: Class<T>
): PendingIntent {
val resultIntent = Intent(context, javaClass)
resultIntent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
val stackBuilder = TaskStackBuilder.create(context)
stackBuilder.addParentStack(javaClass)
stackBuilder.addNextIntent(resultIntent)
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
stackBuilder.getPendingIntent(0, PendingIntent.FLAG_IMMUTABLE)
} else {
stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
}
}
}
提前非常感谢您,我已经尝试修复这个错误好几个星期了,但很难修复,因为一切都对我自己有效。
所以我几乎已经解决了这个问题,不再每周发生数百次崩溃,而是每两天一次。
解决方法是这样的,启动前台服务时:在主线程等待main looper,然后启动即可。更常见的是,现在需要启动服务之前的 5 秒就足够了。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Handler(Looper.getMainLooper()).post{
MyContext.getContext().startForegroundService(Intent(this, NotificationUtil::class.java))
}
} else {
startService(Intent(this, NotificationUtil::class.java))
}
我知道,关于这个错误已经有很多问题了。但是我尝试了很多解决方案,但对我没有任何帮助。我的应用程序中有一个带有计时器的通知服务,crashlytics 报告了数百次崩溃(android 8 - 12),如下所示:
ForegroundServiceDidNotStartInTimeException:
Fatal Exception: android.app.ForegroundServiceDidNotStartInTimeException
Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord{cac9d0b u0 com.malmatech.eggtimer/.NotificationUtil}
android.app.ActivityThread.throwRemoteServiceException (ActivityThread.java:2134)
android.app.ActivityThread.access00 (ActivityThread.java:309)
android.app.ActivityThread$H.handleMessage (ActivityThread.java:2363)
android.os.Handler.dispatchMessage (Handler.java:106)
android.os.Looper.loopOnce (Looper.java:226)
android.os.Looper.loop (Looper.java:313)
android.app.ActivityThread.main (ActivityThread.java:8582)
java.lang.reflect.Method.invoke (Method.java)
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:563)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1133)
和 RemoteServiceException:
Fatal Exception: android.app.RemoteServiceException
Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord{d760a21 u0 com.malmatech.eggtimer/.NotificationUtil}
android.app.ActivityThread$H.handleMessage (ActivityThread.java:2313)
android.os.Handler.dispatchMessage (Handler.java:107)
android.os.Looper.loop (Looper.java:213)
android.app.ActivityThread.main (ActivityThread.java:8178)
java.lang.reflect.Method.invoke (Method.java)
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:513)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1101)
我仔细检查了我的代码并搜索了网络,但没有找到任何东西,也从未在我自己的设备或模拟器上遇到这些异常...
通知仅在计时器为 运行 且应用程序关闭时显示。在我的 TimerActivity 的 onPause() 中,我启动服务:
if (timerState == TimerState.Running){
timer.cancel()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
MyContext.getContext().startForegroundService(Intent(this, NotificationUtil::class.java))
} else {
startService(Intent(this, NotificationUtil::class.java))
}
}
在 onResume() 中我停止了服务:
try {
MyContext.getContext().stopService(
Intent(
MyContext.getContext(),
NotificationUtil::class.java
)
)
} catch (ex: Exception) {
ex.printStackTrace()
}
这是我的服务 class,我删除了一些不相关的代码,但应该包括管理通知的所有内容。
class NotificationUtil : Service() {
override fun onBind(intent: Intent?): IBinder? {
return null
}
var eggCount = 1
private var secondsRemaining: Long = 0
private lateinit var timer: CountDownTimer
// some more, irrelevant for question
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
showNotification()
log("onStartCommand executed with startId: $startId")
if (intent != null) {
val action = intent.action
log("using an intent with action $action")
} else {
log("with a null intent. It has been probably restarted by the system.")
}
// by returning this we make sure the service is restarted if the system kills the service
return START_STICKY
}
override fun onCreate() {
super.onCreate()
//irrelevant Code - getting an array from SharedPreferences and setting up textToSpeech
showNotification()
startTimer()
}
override fun onDestroy() {
super.onDestroy()
hideNotification()
timer.cancel()
}
fun showNotification(done: Boolean = false) {
val nBuilder = NotificationCompat.Builder(applicationContext, "menu_timer")
.setSmallIcon(R.drawable.ic_notification_res_specific)
.setOngoing(true)
.setAutoCancel(true)
.setDefaults(0)
.setContentIntent(
getPendingIntentWithStack(
applicationContext,
TimerActivity::class.java
)
)
.setPriority(PRIORITY_MAX)
.setVisibility(VISIBILITY_PUBLIC)
.setNotificationSilent()
if (!done) {
//irrelecantCode, setting ginishedStr and finishedIndividualString
nBuilder.setContentTitle(getString(R.string.eggTimerRunning))
if (eggCount > 1) {
nBuilder.setStyle(
NotificationCompat.BigTextStyle().bigText(
getString(R.string.remainingTimeNotification) + " $finishedStr\n" + getString(
R.string.nextEggNotification
) + " $finishedIndividualString"
)
)
.setContentText(
getString(R.string.remainingTimeNotification) + " $finishedStr\n" + getString(
R.string.nextEggNotification
) + " $finishedIndividualString"
)
} else {
nBuilder.setStyle(
NotificationCompat.BigTextStyle()
.bigText(getString(R.string.remainingTimeNotification) + " $finishedStr")
)
.setContentText(getString(R.string.remainingTimeNotification) + " $finishedStr")
}
} else {
nBuilder.setContentTitle(getString(R.string.eggTimerDone))
.setStyle(
NotificationCompat.BigTextStyle().bigText(getString(R.string.BonAppetite))
)
.setContentText(getString(R.string.BonAppetite))
}
//irrelevant code
val nManager =
applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
nManager.createNotificationChannel("menu_timer", "Timer App Timer", true)
nManager.notify(135678, nBuilder.build())
val notification: Notification = nBuilder.build()
startForeground(135678, notification)
}
private fun hideNotification() {
val nManager =
applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
nManager.cancel(135678)
}
private fun startTimer() {
timer = object : CountDownTimer(secondsRemaining * 1000, 1000) {
override fun onFinish() = onTimerFinished()
override fun onTick(millisUntilFinished: Long) {
secondsRemaining = millisUntilFinished / 1000
showNotification()
}
}.start()
}
private fun onTimerFinished(ring: Boolean = true) {
if (ring) {
//irrelevant code, ring and vibrate if timer is finished
}
showNotification(true)
}
@TargetApi(26)
private fun NotificationManager.createNotificationChannel(
channelID: String,
channelName: String,
playSound: Boolean
) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channelImportance = if (playSound) NotificationManager.IMPORTANCE_DEFAULT
else NotificationManager.IMPORTANCE_LOW
val nChannel = NotificationChannel(channelID, channelName, channelImportance)
nChannel.enableLights(true)
nChannel.lightColor = Color.BLUE
this.createNotificationChannel(nChannel)
}
}
private fun <T> getPendingIntentWithStack(
context: Context,
javaClass: Class<T>
): PendingIntent {
val resultIntent = Intent(context, javaClass)
resultIntent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
val stackBuilder = TaskStackBuilder.create(context)
stackBuilder.addParentStack(javaClass)
stackBuilder.addNextIntent(resultIntent)
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
stackBuilder.getPendingIntent(0, PendingIntent.FLAG_IMMUTABLE)
} else {
stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
}
}
}
提前非常感谢您,我已经尝试修复这个错误好几个星期了,但很难修复,因为一切都对我自己有效。
所以我几乎已经解决了这个问题,不再每周发生数百次崩溃,而是每两天一次。
解决方法是这样的,启动前台服务时:在主线程等待main looper,然后启动即可。更常见的是,现在需要启动服务之前的 5 秒就足够了。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Handler(Looper.getMainLooper()).post{
MyContext.getContext().startForegroundService(Intent(this, NotificationUtil::class.java))
}
} else {
startService(Intent(this, NotificationUtil::class.java))
}