添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

如何在调用startForeground()方法前停止一个前台服务?

0 人关注

我正在使用以下代码启动一个前台服务

 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    context.startForegroundService(intent);
  } else {
    context.startService(intent);

这将启动一个前台服务。在Android Oreo及以上版本中,我们必须在5秒内调用startForeground()方法。现在在我的服务中,我们做一些处理,如果某些条件没有得到满足,那么我就不调用startForeground()方法。相反,我试图杀死这个服务。

 if (someConditionMet) {
        startForeground(notificationId, notification)
    } else {
        stopSelf()

现在,如果someConditionMet变量为假,那么我的应用程序就会崩溃,崩溃日志如下。

2019-04-10 16:57:25.695 19785-19785/com.awesomedroidapps.foregroundactivity E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.awesomedroidapps.foregroundactivity, PID: 19785
android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord{e78d43f u0 com.awesomedroidapps.foregroundactivity/.ForegroundServiceTest}
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1835)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loop(Looper.java:193)
    at android.app.ActivityThread.main(ActivityThread.java:6863)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:537)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

我不明白,当我停止服务时,为什么要调用startForeground()方法?有什么方法可以让我们在不调用startForeground()方法的情况下停止前台服务吗?

3 个评论
你可以尝试添加stopForeground(true),然后再添加stopSelf()?
也试过这个,没有用
AFAIK,没有办法绕过这一点。我怀疑这个限制是为了防止开发者通过让两个服务交替运行几秒钟而产生相当于一个长期运行的后台服务。
android
thedarkpassenger
thedarkpassenger
发布于 2019-04-10
3 个回答
Gaurav Deochakke
Gaurav Deochakke
发布于 2019-04-10
0 人赞同

你不能。周期。

在startForeground被调用并成功执行之前,你不能停止一个前台服务。在前台服务采取任何行动之前,必须完成这个调用。 无论你使用stopSelf()和stopForeground()的哪种组合,都不能实现你想要的结果。 这里有一篇关于这个问题的很好的文章。 前台服务陷阱

Timur Panzhiev
Timur Panzhiev
发布于 2019-04-10
0 人赞同

如果你想在不创建实际通知的情况下停止服务,你可以直接调用带有存根通知的 startForeground ,并在 stopSelf 被调用后立即取消。

if (conditionMet)
    startForeground(notificationId, notification)
} else {
    startForeground(STUB_NOTIFICATION_ID, createStubNotification())
    stopSelf()
    cancelStubNotification()
private fun createStubNotification(): Notification {
    val notificationManager =
        getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
    if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O) {
        notificationManager.createNotificationChannel(
            NotificationChannel(
                STUB_NOTIFICATION_CHANNEL_ID,
                STUB_NOTIFICATION_CHANNEL_NAME,
                IMPORTANCE_LOW
            ).apply { setShowBadge(false) }
    return with(NotificationCompat.Builder(this, STUB_NOTIFICATION_CHANNEL_ID)) {
        setBadgeIconType(NotificationCompat.BADGE_ICON_NONE)
        setOngoing(true)
        setSmallIcon(R.drawable.ic_notification)
        priority = NotificationCompat.PRIORITY_LOW
        setShowWhen(false)
        setSilent(true)
        build()
    }.also { notificationManager.notify(STUB_NOTIFICATION_ID, it) }
private fun cancelStubNotification() =