首先,我看了这些;
- Context.startForegroundService() did not then call Service.startForeground()
- Context.startForegroundService() did not then call Service.startForeground
- Android 9 (Pie) Only: Context.startForegroundService() did not then call Service.startForeground() - Works fine on Oreo
- RemoteServiceException Context.startForegroundService() did not then call Service.startForeground()
- https://issuetracker.google.com/issues/76112072
我有一个流媒体应用程序,几乎有一百万人在使用。我正在为播放器使用前台服务。我还没有实现MediaSession
。我有99.95%的无崩溃会话。所以这个应用程序可以在所有版本上工作,但我开始在android 9上收到崩溃报告(ANR)。这种崩溃只发生在Samsung
手机上,特别是s9, s9+, s10, s10+, note9
机型。
我试过了,
- 在
onCreate()
中调用startForeground()
方法 - 在
Context.stopService()
之前调用Service.startForeground()
- 其他堆栈溢出类似问题的答案
我看了一些谷歌开发者的评论,他们说这只是Intended Behavior
。我想知道这是三星的系统还是Android操作系统发生的。有人对此有意见吗?我该如何解决这个问题?
8条答案
按热度按时间ryhaxcpt1#
经过太多的斗争与此崩溃终于,我修复了这个异常完全找到解决方案。
请确保在您的服务中做过这些事情,我将它们列出如下:(有些东西是重复的,正如在另一个答案中提到的,我只是再写一遍)。
1-呼叫
开始前景()
在onCreate和onStartCommand中。(可以多次调用startForeground())
2-停止您的服务使用
停止服务()
,则无需调用stopForeground()或stopSelf()。
3-启动服务时使用
上下文兼容启动前台服务()
它将处理不同的API版本。
4-如果您的服务具有操作(需要待定意图)使用广播接收器而不是当前服务处理待定意图(它将在Create()上调用您的服务,这可能很危险,或者使用PendingIntent.FLAG_NO_CREATE),因此,最好使用特定的广播接收器来处理您的服务通知操作,我的意思是使用**PendingIntent.getBroadcast()**创建所有待定Intent。
5-始终在停止服务之前确保已创建并启动服务(I创建具有我的服务状态的全局类)
6-将notificationId设置为一个长数字,例如121412。
7-使用NotificationCompat.Builder将处理不同的API版本,您只需为构建版本〉= Build.VERSION_CODES.O.创建通知通道。(这不是一个解决方案,只是使您的代码更具可读性)
8-加
权限到你的清单。(这一个在android文档中提到)Android Foreground Service
希望对你有帮助:))
wkyowqbh2#
我一直在等待我的崩溃报告分享解决方案。我没有得到任何崩溃或ANR近20天。我想分享我的解决方案。它可以帮助那些谁遇到这个问题。
在
onCreate()
方法中onCreate()
. Official doc的顶部创建一个通知通道Context.startForegroundService()
方法之后调用Service.startForeground()
方法。在我的prepareAndStartForeground()
方法中。注意:我不知道为什么**ContextCompat.startForegroundService()**不能正常工作。
因此,我手动将相同的函数添加到我的服务类中,而不是调用
ContextCompat.startForegroundService()
prepareAndStartForeground()
方法这是我的
onCreate()
我的
onStartCommand()
onRebind
、onBind
、onUnbind
方法,例如调用onDestroy()时需要清除一些内容
我希望这个解决方案对您有效。
dkqlctbz3#
Android
Service
组件要正常工作有点棘手,尤其是在操作系统增加了额外限制的更高版本的Android上。正如其他答案中提到的,当启动Service
时,使用ContextCompat.startForegroundService()
。接下来,在Service.onStartCommand()
中,立即调用startForeground()
。将您要显示的Notification
存储为成员字段,并使用它,除非它为null。示例:总是在
Service
中返回START_STICKY
。其他任何东西都可能是错误的,特别是如果你正在做一个任何类型的音频播放器。事实上,如果你正在做一个音频播放器,你不应该实现自己的服务,而是使用MediaBrowserServiceCompat
(来自AndroidX)。我也推荐我写的博客文章:https://hellsoft.se/how-to-service-on-android-part-3-1e24113152cd
mwecs4sa4#
我浪费了太多时间去弄清楚它为什么会崩溃,却不明白为什么。问题出在
startForeground()
的通知ID上。把它改成0以外的东西。这是用安卓11运行的。bihw5rsg5#
在相同的手机上遇到同样的问题后,我做了一些改变,崩溃也消失了。我不知道是什么造成了这个问题,但我猜是在onCreate和onStartCommand中调用startForeground。我不知道如果服务已经启动,并且在onCreate中正确调用了所有内容,为什么需要这样做。
其他变更:- 将serviceId更改为某个较低的数字(1-10)-减少通过单例同步类调用startFororegroundService的频率(以前在崩溃时实现了此功能,以防止在服务通过onStartCommand的回调启动之前停止服务,但现在如果服务已经启动,它还会过滤调用)。-使用START_REDELIVER_INTENT(应该不会影响任何内容)
这个问题一直发生在提到的手机只是一些用户,所以我怀疑这是有关一些新的更新,从三星,并最终将得到修复
acruukt96#
我几乎消除了MediaSessionCompat.回调方法(如onPlay()、onPause())中startForeground()的问题。
nhjlsmyf7#
根据这个错误消息,这说明当你调用Context.startForegroundService()时,你必须使用Service.startForeground()方法发出通知。
oxcyiej78#
2022年12月13日更新
我在音乐播放器应用程序中遇到此问题
然后,上下文.startForegroundService()没有调用服务.startForeground()
经过大量的研究,我找到了一些解决办法,也许这会帮助其他人
解决方案1:
如果您的应用面向API级别26或更高级别,则当应用本身不在前台时,系统会对后台服务的运行施加限制。如果应用需要创建前台服务,则应用应调用
startForegroundService()
。即使应用在后台,系统也允许应用调用Context.startForegroundService()
。但是,应用程序必须在创建服务后5秒内调用该服务的startForeground()
方法。**注意:**在
onCreate()
中调用startForeground()
,以获取您使用Context.startForegroundService()
的服务为什么会发生这个问题,因为Android框架不能保证您的服务在5秒内启动,但另一方面,框架确实有一个严格的限制前台通知必须在5秒内发射,如果不检查框架是否已尝试启动服务
startForeground()
,则通知必须同时位于onCreate()
和onStartCommand()
中,因为如果您的服务已创建并且活动正在尝试重新启动它,将不会调用onCreate()
。通知ID不能为0,否则即使原因不同,也会发生相同的崩溃。不能在startForeground
之前调用stopSelf
。后台服务限制:
app服务有5秒时间调用
startForeground()
,app未在时限内调用startForegroudn()
,系统停止服务并声明app为ANR。可能性:
1.在调用
startForeground()
方法之前,前台服务被破坏/完成。1.或者前台服务已经示例化,再次被调用,则不调用
onCreate()
方法,调用onStartCommand()
,然后将逻辑移到onStartCommand()
调用startForeground()
方法。startForeground()
中的通知ID不能为0,否则也会导致崩溃。解决方案2:
1.在
onCreate()
和onStartCommand()
中调用startForeground()
(可以多次调用startForeground()
)1.使用
context.stopService()
停止服务,无需致电stopForeground()
或stopSelf()
1.使用
ContextCompat.startForegroundService()
启动您的服务。它将处理不同的API。1.如果你的服务有动作(需要待定Intent)用广播接收器而不是你当前的服务来处理你的待定Intent(它将在
onCreate()
中调用你的服务并且可能是危险的,或者使用PendingIntent.FLAG_NO_CREATE
),这是好的)。练习用一个特定的广播接收器来处理你的服务通知动作,我的意思是使用PendingIntent.getBroadcast()
创建所有你的待定Intent。1.一些崩溃报告来自与在Oreo中处理
BOOT_COMPLETED
相关的问题1.基本上,一旦你执行
startForegroundService()
,你就必须执行startForeground()
。如果你不能在你的服务中执行startForeground()
,那么你最好在你的广播接收器中执行这种类型的检查,等等--这样你就只有在确定要执行startForeground()的时候才启动服务1.按如下方式添加
Handler()
:Handler().postDelayed(()>ContextCompat.startForegroundService(activity, new Intent(activity, ChatService.class)), 500);
解决方案3:
使用什么来代替前台服务?
现在有
JobScheduler
和JobService
,它们是前台服务的更好的替代品。这是一个更好的选择,因为:作业运行时,系统会代表您的应用保留唤醒锁。因此,您无需采取任何操作来保证设备在作业期间保持唤醒状态。这意味着你不再需要关心唤醒锁的处理,这就是为什么它与前台服务没有什么不同。从实现的Angular 来看,
JobScheduler
不是你的服务,它是一个系统的服务,大概它会正确地处理队列,谷歌永远不会终止自己的孩子。Samsung已在其Samsung附件协议中从
startForegroundService
切换为JobScheduler
和JobService
当智能手表等设备需要与手机等主机通信时,这一功能非常有用,因为任务需要通过应用程序的主线程与用户交互。由于任务是由调度程序发布到主线程的,不过你应该记住,作业是在主线程上运行的,把所有繁重的工作都卸载到其他线程和异步任务上。解决方案4:
问题是从服务本身调用
Service.startForeground(id, notification)
,对吗?不幸的是,Android Framework不能保证在5秒内调用Service.onCreate()
,但无论如何都会抛出异常,所以我想出了这种方法。在调用Context.startForegroundService()
之前,使用绑定器将服务绑定到上下文如果绑定成功,则从服务连接调用
Context.startForegroundService()
,并立即在服务连接内部调用Service.startForeground()
。**重要提示:**在try-catch中调用
Context.bindService()
方法,因为在某些情况下,调用可能会引发异常,在这种情况下,您需要依赖于直接调用Context.startForegroundService()
,并希望它不会失败。例如,广播接收器上下文,但是在这种情况下,获取应用程序上下文不会引发异常,但直接使用上下文会引发异常。解决方案5:
如果您调用
Context.startForegroundService(...)
,然后在调用Service.startForeground(...)
之前调用Context.stopService(...)
,您的应用将崩溃。信息由google团队提供
这不是一个框架错误;如果应用使用
startForegroundService()
启动服务示例,它必须将该服务示例转换到前台状态并显示通知。如果服务示例在调用startForeground()
之前停止,则该承诺无法实现:这是应用程序中的漏洞。发布一个其他应用可以直接启动的服务从根本上说是不安全的。2你可以通过将该服务的所有启动操作都视为需要
startForeground()
来减轻这一点,尽管很明显这可能不是你所想的。解决方案6:
我能够消除所有的崩溃。我所做的是删除对
stopSelf()
的调用。(我考虑延迟停止,直到我非常确定通知显示,但我不希望用户看到通知,如果它是不必要的。)当服务已经空闲了一分钟或系统正常销毁它,没有抛出任何异常。解决方案7:
与前台服务使用相关的常见崩溃是:
然后,上下文.startForegroundService()没有调用服务.startForeground()
要摆脱这种情况,请使用以下策略:
不要将服务作为前台服务启动,而是将服务作为后台服务启动并绑定到它,然后当您的Activity/UI组件中有可用的服务示例时,您可以直接调用服务内部的方法,该方法调用
Service.startForeground()
并添加通知。这听起来像是一个黑客攻击,但想想像Spotify这样的音乐应用程序是如何启动服务的。这是一个类似的方法。结果非常出色。使用这种方法,问题数量从一个显著的无法揭示的数字减少到0。