Ich arbeite derzeit an einer App für die Audiowiedergabe und verwende einen gestarteten gebundenen Dienst, um Musik im Hintergrund abzuspielen. Ich starte und binde mit folgendem Code an den Dienst.
val intent = Intent(context, MusicService::class.Java)
context.startService(intent)
context.bindService(intent, serviceConnection, 0)
Es wird beim Abspielen in den Vordergrund befördert und beim Anhalten der Musik herabgestuft.
// onAudioPlay
service.startForeground(NOTIFY_ID, notification)
// onAudioPause
service.stopForeground(false)
Service funktioniert bisher einwandfrei. Wenn der Benutzer die Benachrichtigung im angehaltenen Zustand durchwischt (entfernt), stürzt der Dienst nach einigen Sekunden ab und gibt diesen Fehler aus.
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.myplayer, PID: 4380
Android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground()
Android.app.ActivityThread$H.handleMessage(ActivityThread.Java:1775)
Android.os.Handler.dispatchMessage(Handler.Java:105)
Android.os.Looper.loop(Looper.Java:164)
Android.app.ActivityThread.main(ActivityThread.Java:6541)
Java.lang.reflect.Method.invoke(Native Method)
com.Android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.Java:240)
com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:767)
Dies passiert nur auf Oreo und ich habe bereits über die Hintergrundbeschränkungen in Oreo gelesen. Aber folgende Punkte nerven mich.
Warum stürzt der Dienst ab? Was mache ich falsch? Ich bin sehr dankbar, wenn mir jemand sagt, was hier passiert.
Zum Erweitern auf deshUks Antwort - jede Verwendung von MediaButtonReceiver
(entweder Erstellen ausstehender Absichten oder nur Empfangen von Medienknopf-Absichten) kann dazu führen, dass Ihr Dienst mit startForegroundService
aufgerufen wird, weil MediaButtonReceiver.onReceive
startet Ihren Dienst auf diese Weise auf Oreo. Ich habe das nirgendwo dokumentiert gesehen.
Sie müssen diese Methode in Ihrer Service-Klasse onCreate () aufrufen: ->
private void startServiceOreoCondition(){
if (Build.VERSION.SDK_INT >= 26) {
String CHANNEL_ID = "my_service";
String CHANNEL_NAME = "My Background Service";
NotificationChannel channel = new NotificationChannel(CHANNEL_ID,
CHANNEL_NAME,NotificationManager.IMPORTANCE_NONE);
((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(channel);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setCategory(Notification.CATEGORY_SERVICE).setSmallIcon(R.drawable.ic_tgc_icon).setPriority(PRIORITY_MIN).build();
startForeground(101, notification);
}
}
Ich habe das Problem gefunden. In meiner Benachrichtigung habe ich eingestellt
setDeleteIntent(MediaButtonReceiver.buildMediaButtonPendingIntent(service, PlaybackStateCompat.ACTION_STOP))
Wenn der Benutzer die Benachrichtigung entfernt, ruft er startForegroundService () auf, da ich zuvor stopForeground () aufgerufen habe, als ich angehalten habe.
Um dies zu überwinden, habe ich eine benutzerdefinierte ausstehende Absicht verwendet und sie in onStartCommand()
anstelle von MediaButtonReveiver's PendingIntent behandelt
Aus den Dokumenten 8.0 Verhaltensänderungen
Das System ermöglicht Apps, Context.startForegroundService () aufzurufen, auch wenn sich die App im Hintergrund befindet. Die App muss jedoch die startForeground () - Methode dieses Dienstes innerhalb von fünf Sekunden nach dem Erstellen des Dienstes aufrufen.
Sie müssen also startForeground in onCreate () für Ihren Dienst aufrufen.
Spät zur Party, aber wie schon erwähnt, ist es das MediaButtonReceiver
; es hat diesen Code:
@Override
public void onReceive(Context context, Intent intent) {
...
startForegroundService(context, intent);
...
}
Ich verwende den Empfänger in einem gebundenen Dienst, also habe ich eine Klasse erstellt, die bis auf diese Zeile genau den gleichen Code wie MediaButtonReceiver
hat. Ich habe es ersetzt durch:
context.startService(intent);