web-dev-qa-db-fra.com

Erreur de service lié avec "Context.startForegroundService () n'a pas alors appelé Service.startForeground ()" erreur

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.

  • Ce service est un service lié (qui n'est pas affecté par des limitations)
  • Je n'ai jamais utilisé Context.startForegroundService () pour démarrer le service (et je ne veux pas l'utiliser).
  • Le service ne plante pas lorsqu'il est rétrogradé au premier plan, cela se produit lors de la suppression de la notification.

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.

21
UdeshUK

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.

12
Andy S

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);
        }
    }
8
Ramkailash

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

6
UdeshUK

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.

2
lakshman.pasala

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);
1
UpsideDownTree