web-dev-qa-db-fra.com

startForegroundService () n'a pas appelé startForeground (), mais il l'a fait

J'ai la Context.startForegroundService() did not then call Service.startForeground() dans mon Android Android, mais je ne peux pas comprendre pourquoi cela se produit.

Mon application est destinée à la diffusion multimédia en continu, et cette erreur ne se produit que lorsque vous vous arrêtez à partir de la notification de premier plan (en la transformant en notification régulière), et que vous glissez ensuite la notification, ce qui est destiné à arrêter mon service.

Voici la seule méthode où les méthodes startForegroundService, startForeground et stopForeground sont appelées:

private void configureServiceState(long action) {
        if (action == PlaybackStateCompat.ACTION_PLAY) {
            if (!mServiceInStartedState) {
                ContextCompat.startForegroundService(
                        StreamingService.this,
                        new Intent(
                                StreamingService.this,
                                StreamingService.class));
                mServiceInStartedState = true;
            } startForeground(NOTIFICATION_ID,
                    buildNotification(PlaybackStateCompat.ACTION_PAUSE));
        } else if (action == PlaybackStateCompat.ACTION_PAUSE) {
            stopForeground(false);

            NotificationManager mNotificationManager
                    = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

            assert mNotificationManager != null;
            mNotificationManager
                    .notify(NOTIFICATION_ID,
                            buildNotification(PlaybackStateCompat.ACTION_PLAY));
        } else if (action == PlaybackStateCompat.ACTION_STOP) {
            mServiceInStartedState = false;
            stopForeground(true);
            stopSelf();
        }
    }

Et voici où l'intention de suppression de ma notification est définie:

.setDeleteIntent(
                        MediaButtonReceiver.buildMediaButtonPendingIntent(
                                this, PlaybackStateCompat.ACTION_STOP));

Cette méthode configureServiceState(long action) est appelée uniquement à partir de mes rappels MediaSession: onPlay, onPause et onStop... évidemment avec l'action étant l'action prévue à effectuer.

L'erreur ne se produit pas lors de l'exécution de onStop à partir de mon interface utilisateur ou lors de l'appel de onPause suivi de onStop à partir de l'interface utilisateur (en miroir de l'action requise pour effacer la notification), uniquement de la notification.

Tout ce que je peux trouver à propos de cette erreur est qu'elle se produit soi-disant lorsque vous appelez startForegroundService mais n'appelez pas startForeground dans les 5 secondes ... cependant le startForeground est invoqué immédiatement après la seule fois que startForegroundService est invoquée.

De plus, un onPlaybackStateChange va à mon activité 'Now Playing' dans la méthode onStop, ce qui déclenche cette activité pour exécuter finish() afin que le service ne soit pas redémarré façon.

Qu'est-ce que j'oublie ici?

Détails supplémentaires:

  • Le service n'est pas partiellement redémarré par mon activité "en cours de lecture" car l'exécution du code n'atteint aucune de ses méthodes.

  • L'exécution du code ne semble également jamais ressaisir configureServiceState avant que l'erreur ne se produise

  • Si j'ajoute un point d'arrêt au dernier point possible (MediaButtonReceiver.handleIntent(mMediaSession, intent); dans onStartCommand de mon service), la suspension de l'exécution ici et la tentative de débogage provoquent la déconnexion du débogueur peu de temps après la pause

  • Essayer un canal de notification différent pour le premier plan par rapport à la notification régulière ne fait aucune différence non plus

  • Faire glisser la notification interrompue hors de l'écran de verrouillage ne provoque pas d'erreur, elle ne se produit que si le téléphone est déverrouillé; que mon application soit ouverte ou non

Exception complète:

Android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground()
                      at Android.app.ActivityThread$H.handleMessage(ActivityThread.Java:1870)
                      at Android.os.Handler.dispatchMessage(Handler.Java:105)
                      at Android.os.Looper.loop(Looper.Java:164)
                      at Android.app.ActivityThread.main(ActivityThread.Java:6809)
                      at Java.lang.reflect.Method.invoke(Native Method)
                      at com.Android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.Java:240)
                      at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:767)

Mon appareil de test fonctionne Android 8.0, l'API min du projet est 21 et l'API cible est 27. L'API appareil est 26.

10
transiti0nary

Vous devez utiliser un NotificationChannel pour Android O API 26 et supérieur, sinon vous obtiendrez l'erreur que vous avez rencontrée. Consultez la déclaration suivante dans le Android docs - Créer et gérer des canaux de notification :

À partir de Android 8.0 (API niveau 26), toutes les notifications doivent être attribuées à un canal.

Voici un extrait (prenez-en ce dont vous avez besoin) d'une méthode que j'utilise pour construire nos notifications multimédias. Vous pouvez voir qu'il y a une vérification pour les appareils Android O avec une méthode spécifique pour gérer ce cas:

private fun compileNotification(context: Context, action: NotificationCompat.Action, mediaSession: MediaSessionCompat, controller: MediaControllerCompat, mMetadata: MediaMetadataCompat, art: Bitmap?, mPlaybackState: PlaybackStateCompat) {

    val description = mMetadata.description

    // https://stackoverflow.com/questions/45395669/notifications-fail-to-display-in-Android-oreo-api-26
    @TargetApi(26)
    if(Utils.hasO()) {
        val channelA = mNotificationManager?.getNotificationChannel(NotificationChannelID.MEDIA_SERVICE.name)

        if(channelA == null) {
            val channelB = NotificationChannel(NotificationChannelID.MEDIA_SERVICE.name,
                    "MediaService",
                    NotificationManager.IMPORTANCE_DEFAULT)
            channelB.setSound(null, null)

            mNotificationManager?.createNotificationChannel(channelB)
        }
    }

    val notificationBuilder = if(Utils.hasLollipop()) {
        NotificationCompat.Builder(context, NotificationChannelID.MEDIA_SERVICE.name)
    } else {
        NotificationCompat.Builder(context)
    }

    notificationBuilder
            .setStyle(Android.support.v4.media.app.NotificationCompat.MediaStyle()
                    // Show actions 0,2,4 in compact view
                    .setShowActionsInCompactView(0,2,4)
                    .setMediaSession(mediaSession.sessionToken))
            .setSmallIcon(R.drawable.logo_icon)
            .setShowWhen(false)
            .setContentIntent(controller.sessionActivity)
            .setContentTitle(description.title)
            .setContentText(description.description)
            .setLargeIcon(art)
            .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
            .setOngoing(mPlaybackState.state == PlaybackStateCompat.STATE_PLAYING)
            .setOnlyAlertOnce(true)

            if(!Utils.hasLollipop()) {
                notificationBuilder
                        .setStyle(Android.support.v4.media.app.NotificationCompat.MediaStyle()
                                // Show actions 0,2,4 in compact view
                                .setShowActionsInCompactView(0,2,4)
                                .setMediaSession(mediaSession.sessionToken)
                                .setShowCancelButton(true)
                                .setCancelButtonIntent(MediaButtonReceiver.buildMediaButtonPendingIntent(context,
                                        PlaybackStateCompat.ACTION_STOP)))
                        // Stop the service when the notification is swiped away
                        .setDeleteIntent(MediaButtonReceiver.buildMediaButtonPendingIntent(context,
                                PlaybackStateCompat.ACTION_STOP))
            }

    notificationBuilder.addAction(NotificationCompat.Action(
            R.drawable.exo_controls_previous,
            "Previous",
            MediaButtonReceiver.buildMediaButtonPendingIntent(context,
                    PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS)))
    notificationBuilder.addAction(NotificationCompat.Action(
            R.drawable.ic_replay_10_white_24dp,
            "Rewind",
            MediaButtonReceiver.buildMediaButtonPendingIntent(context,
                    PlaybackStateCompat.ACTION_REWIND)))

    notificationBuilder.addAction(action)

    notificationBuilder.addAction(NotificationCompat.Action(
            R.drawable.ic_forward_10_white_24dp,
            "Fast Foward",
            MediaButtonReceiver.buildMediaButtonPendingIntent(context,
                    PlaybackStateCompat.ACTION_FAST_FORWARD)))
    notificationBuilder.addAction(NotificationCompat.Action(
            R.drawable.exo_controls_next,
            "Next",
            MediaButtonReceiver.buildMediaButtonPendingIntent(context,
                    PlaybackStateCompat.ACTION_SKIP_TO_NEXT)))

    (context as MediaService).startForeground(NOTIFICATION_ID, notificationBuilder.build())
}

Dans votre rappel onStop(), vous devrez appeler stopSelf() au sein du service. Ensuite, lorsque votre méthode service onDestroy() est appelée, vous devez nettoyer quelques éléments (comme cela s'applique à votre cas) comme suit:

override fun onDestroy() {
    super.onDestroy()

    abandonAudioFocus()
    unregisterReceiver(mNoisyReceiver)

    //Deactivate session
    mSession.isActive = false
    mSession.release()

    NotificationManagerCompat.from(this).cancelAll()

    if(mWiFiLock?.isHeld == true) mWiFiLock?.release()

    stopForeground(true)
}

Je n'ai pas inclus de détails pour certaines des méthodes ci-dessus, mais les noms des méthodes doivent être auto-commentés - faites-moi savoir si je peux inclure plus de détails. Certains d'entre eux peuvent être exagérés, mais dans votre cas, cela pourrait résoudre le problème.

Je suis sûr que cela résoudra votre problème. Si ce n'est pas le cas, j'ai encore quelques idées.

5
YodaScholtz

Juste perdu trop d'heures à ce sujet. Je ne suis pas sûr que ce soit ce que vous vivez, mais dans mon cas, j'ai continué à recevoir cette exception parce que mon NOTIFICATION_ID était 0 ... L'utilisation d'une autre valeur semble résoudre ce problème.-_-

5
tobalr

J'ai eu le même problème. Le problème était d'utiliser PendingIntent.getForegroundService() sur les éléments de notification, cliquez pour mettre à jour le service multimédia. Utiliser simplement PendingIntent.getService a résolu le problème pour moi.

1
Pitt90