首先, 我看着这些;
我有将近一百万人使用的流应用程序。我正在为播放器使用前台服务。我还没有实现MediaSession
。我有99.95%的无崩溃会话。
因此,此应用可以在所有版本上使用,但是我开始使用android 9收到崩溃报告(ANR)。此崩溃仅发生在Samsung
手机,尤其是s9, s9+, s10, s10+, note9
机型上。
我尝试过这些,
startForeground()
中调用onCreate()
方法Service.startForeground()
之前致电Context.stopService()
我阅读了Google开发人员的一些评论,他们说这仅仅是Intended Behavior
。我想知道这是由三星的系统还是Android操作系统引起的。有人对此有意见吗?我该如何解决?
答案 0 :(得分:5)
经过与这次崩溃的过多斗争之后,我彻底修复了此异常并找到了解决方案。
确保已在您的服务中完成了这些工作,我将它们列出如下: (其中的一些内容是重复的,正如我在另一个答案中再次提到的那样)。
1-通话
startForeground()
在 onCreate 和 onStartCommand 中。(可以多次调用startForeground()是可以的)
@Override
public void onCreate() {
super.onCreate();
startCommand();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent == null) {
return START_NOT_STICKY;
}
final int command = intent.getIntExtra(MAIN_SERVICE_COMMAND_KEY, -1);
if (command == MAIN_SERVICE_START_COMMAND) {
startCommand();
return START_STICKY;
}
return START_NOT_STICKY;
}
private void startCommand() {
createNotificationAndStartForeground();
runningStatus.set(STARTED);
}
2- 使用
停止您的服务context.stopService()
,无需调用 stopForeground()或 stopSelf()。
try {
context.stopService(
new Intent(
context,
NavigationService.class
)
);
} catch (Exception ex) {
Crashlytics.logException(ex);
LogManager.e("Service manager can't stop service ", ex);
}
3- 使用
开始您的服务ContextCompat.startForegroundService()
它将处理不同的API版本。
ContextCompat.startForegroundService(
context,
NavigationService.getStartIntent(context)
);
4-如果您的服务有操作(需要待处理的意图),请使用广播接收器而不是当前的服务来处理您的待处理意图(它将在以下时间调用您的服务) Create()可能很危险,或者使用PendingIntent.FLAG_NO_CREATE),这是一个好的做法,拥有一个特定的Broadcast接收器来处理您的服务通知操作,我的意思是使用 PendingIntent.getBroadcast()创建所有待处理的意图。 strong>。
private PendingIntent getStopActionPendingIntent() {
final Intent stopNotificationIntent = getBroadCastIntent();
stopNotificationIntent.setAction(BROADCAST_STOP_SERVICE);
return getPendingIntent(stopNotificationIntent);
}
private PendingIntent getPendingIntent(final Intent intent) {
return PendingIntent.getBroadcast(
this,
0,
intent,
0
);
}
new NotificationCompat.Builder(this, CHANNEL_ID)
.addAction(
new NotificationCompat.Action(
R.drawable.notification,
getString(R.string.switch_off),
getStopActionPendingIntent()
)
)
5-始终在停止服务之前,确保已创建并启动您的服务(我创建了一个具有我的服务状态的全局类)
if (navigationServiceStatus == STARTED) {
serviceManager.stopNavigationService();
}
6-将您的 notificationId 设置为长号,例如121412。
7-使用 NotificationCompat.Builder 将处理不同的API版本,您只需要为Build版本> = Build.VERSION_CODES.O创建通知通道即可。(这不是一个解决方案,仅使您的代码更具可读性)
8-添加
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
权限到您的清单。 (android docs中提到了这一点) Android Foreground Service
希望它会有所帮助:))
答案 1 :(得分:1)
我正在等待崩溃报告以分享解决方案。近20天我没有发生任何崩溃或ANR。我想分享我的解决方案。它可以帮助遇到此问题的人。
在onCreate()
方法中
onCreate()
的顶部创建一个通知频道。 Official doc Service.startForeground()
方法之后调用Context.startForegroundService()
方法。用我的prepareAndStartForeground()
方法。
注意:我不知道为什么,但是 ContextCompat.startForegroundService()无法正常工作。
由于这个原因,我向服务类中手动添加了相同的功能,而不是调用ContextCompat.startForegroundService()
private fun startForegroundService(intent: Intent) {
if (Build.VERSION.SDK_INT >= 26) {
context.startForegroundService(intent)
} else {
// Pre-O behavior.
context.startService(intent)
}
}
prepareAndStartForeground()
方法
private fun prepareAndStartForeground() {
try {
val intent = Intent(ctx, MusicService::class.java)
startForegroundService(intent)
val n = mNotificationBuilder.build()
// do sth
startForeground(Define.NOTIFICATION_ID, n)
} catch (e: Exception) {
Log.e(TAG, "startForegroundNotification: " + e.message)
}
}
这是我的onCreate()
override fun onCreate() {
super.onCreate()
createNotificationChannel()
prepareAndStartForeground()
}
我的onStartCommand()
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if (intent == null) {
return START_STICKY_COMPATIBILITY
} else {
//....
//...
}
return START_STICKY
}
onRebind
,onBind
,onUnbind
这样的方法
internal var binder: IBinder? = null
override fun onRebind(intent: Intent) {
stopForeground(true) // <- remove notification
}
override fun onBind(intent: Intent): IBinder? {
stopForeground(true) // <- remove notification
return binder
}
override fun onUnbind(intent: Intent): Boolean {
prepareAndStartForeground() // <- show notification again
return true
}
当onDestroy()调用时,我们需要清除一些东西
override fun onDestroy() {
super.onDestroy()
releaseService()
}
private fun releaseService() {
stopMedia()
stopTimer()
// sth like these
player = null
mContext = null
afChangeListener = null
mAudioBecomingNoisy = null
handler = null
mNotificationBuilder = null
mNotificationManager = null
mInstance = null
}
我希望该解决方案对您来说正确。
答案 2 :(得分:0)
在使用同一部手机遇到同样的问题后,我进行了一些更改,然后崩溃消失了。我不确定是什么原因导致的,但我猜想 onCreate和onStartCommand中的startForeground。我不确定如果已经启动服务并且在onCreate中正确调用了所有内容,为什么需要这样做。
其他更改: -将serviceId更改为较低的数字(1-10) -通过单例同步类较少地调用startFororegroundService(这是在崩溃之前实现的,以防止在通过onStartCommand的回调启动服务之前停止服务,但是现在,如果服务已经启动,它也可以过滤调用)。 -使用START_REDELIVER_INTENT(不会有任何影响)
问题仅在某些用户的手机上出现,所以我怀疑这与三星的一些新更新有关,最终将得到解决
答案 3 :(得分:0)
Android {'user_name': 'xcv', 'age': 27, 'country': 'value', 'work_history': [{'name': 'CSC', 'location': 'chennai'}, {'name': 'crayon', 'location': 'chennai'}], 'marital_status': 'married}
组件很难正常工作,尤其是在OS附加了更多限制的更高版本的Android上。如其他答案所述,在启动Service
时,请使用Service
。接下来,在ContextCompat.startForegroundService()
中,立即调用Service.onStartCommand()
。将要显示的startForeground()
存储为成员字段,并使用它,除非它为null。示例:
Notification
始终在您的private var notification:Notification? = null
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if (notification == null) {
notification = createDefaultNotification()
}
startForeground(NOTIFICATION_ID, notification)
// Do any additional setup and work herre
return START_STICKY
}
中返回START_STICKY
。其他任何事情都可能是错误的事情,尤其是当您在做任何类型的音频播放器时。实际上,如果您正在使用音频播放器,则不应实施自己的服务,而应使用MediaBrowserServiceCompat
(来自AndroidX)。
我还推荐我在此撰写的博客文章:https://hellsoft.se/how-to-service-on-android-part-3-1e24113152cd
答案 4 :(得分:0)
我几乎消除了MediaSessionCompat.start回调方法(例如onPlay(),onPause())中的startForeground()问题。
答案 5 :(得分:0)
根据此错误消息,这表示当您调用Context.startForegroundService()时,必须使用Service.startForeground()方法发出通知。这就是我的理解。