Je travaille actuellement sur une application de lecture audio et j'utilise un service lié démarré pour lire de la musique en arrière-plan. Je lance et lie au service en utilisant le code suivant.
val intent = Intent(context, MusicService::class.Java)
context.startService(intent)
context.bindService(intent, serviceConnection, 0)
Il est promu au premier plan lors de la lecture et est rétrogradé lorsque la musique est en pause.
// onAudioPlay
service.startForeground(NOTIFY_ID, notification)
// onAudioPause
service.stopForeground(false)
Le service fonctionne bien jusqu'à présent. Mais lorsque la notification est effacée (supprimée) par l'utilisateur à l'état de pause, le service se bloque après quelques secondes, générant cette erreur.
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)
Cela ne se produit que sur Oreo et j'ai déjà lu des informations sur les limitations d'arrière-plan d'Oreo. Mais les points suivants me bugs.
Pourquoi le service plante-t-il? Qu'est-ce que je fais mal? Je suis très reconnaissant si quelqu'un me dit ce qui se passe ici.
Pour développer réponse de UdeshUk - toute utilisation de MediaButtonReceiver
(soit en train de construire des intentions en attente ou simplement de recevoir des intentions de boutons multimédias) peut entraîner l'appel de votre service avec startForegroundService
, car MediaButtonReceiver.onReceive
commence ainsi votre service sur Oreo. Je n'ai jamais vu cela documenté nulle part.
Vous devez appeler cette méthode dans la méthode onCreate () de la classe Service: ->
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);
}
}
J'ai trouvé le problème. Dans ma notification j'ai mis
setDeleteIntent(MediaButtonReceiver.buildMediaButtonPendingIntent(service, PlaybackStateCompat.ACTION_STOP))
Ainsi, lorsque l'utilisateur supprime la notification, il appelle startForegroundService (), car j'avais précédemment appelé stopForeground () lors d'une pause.
Pour vaincre, j'ai utilisé une intention en attente personnalisée et l'ai traitée dans la onStartCommand()
au lieu de MediaButtonReveiver's PendingIntent
De la documentation 8.0 Changements de comportement
Le système permet aux applications d'appeler Context.startForegroundService () même lorsque l'application est en arrière-plan. Toutefois, l'application doit appeler la méthode startForeground () de ce service dans les cinq secondes suivant sa création.
Vous devez donc appeler startForeground dans onCreate () pour votre service.
En retard à la fête, mais comme cela a été mentionné précédemment, c'est le MediaButtonReceiver
; il a ce code:
@Override
public void onReceive(Context context, Intent intent) {
...
startForegroundService(context, intent);
...
}
J'utilise le récepteur dans un service lié. J'ai donc créé une classe qui a exactement le même code que MediaButtonReceiver
, à l'exception de cette ligne. Je l'ai remplacé par:
context.startService(intent);