startForegroundService() не вызывал startForeground(), но вызывал

у меня Context.startForegroundService() did not then call Service.startForeground() в моем Android-сервисе, но я не могу понять, почему это происходит.

мое приложение предназначено для потоковой передачи мультимедиа, и эта ошибка возникает только тогда, когда вы приостанавливаете уведомление на переднем плане (превращая его в обычное уведомление), а затем удаляете уведомление, которое предназначено для остановки моей службы.

вот единственный метод, где startForegroundService, startForeground и stopForeground методы называются:

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();
        }
    }

и вот где устанавливается цель удаления моего уведомления:

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

этой configureServiceState(long action) метод вызывается только из my MediaSession обратные вызовы: onPlay, onPause и onStop... очевидно, с действием, которое должно быть выполнено.

ошибка не возникает при выполнении onStop из моего пользовательского интерфейса или при вызове onPause следовал по onStop из пользовательского интерфейса (зеркальное отображение действия, необходимого для очистки уведомления), только из уведомление.

все, что я могу найти об этой ошибке, это то, что она предположительно происходит, когда вы вызываете startForegroundService но не называй startForeground в течение 5 секунд... однако startForeground вызывается сразу после единственного времени startForegroundService вызывается.

кроме того,onPlaybackStateChange собирается мой "сейчас играет" активность в onStop метод, который запускает это действие для запуска finish() так что служба не перезапускается таким образом.

чего мне не хватает здесь?

дополнительная информация:

  • служба не частично перезапускается моей активностью "теперь играет", поскольку выполнение кода никогда не достигает ни одного из своих методов.

  • выполнение кода также никогда не повторяется configureServiceState до возникновения ошибки

  • если я добавлю точку останова в последней возможной точке (MediaButtonReceiver.handleIntent(mMediaSession, intent); на onStartCommand моей службы), приостановив выполнение здесь и пытаясь debug заставляет отладчик отключаться вскоре после приостановки

  • попытка другого канала уведомления для переднего плана против обычного уведомления также не имеет значения

  • проводя приостановленное уведомление от экрана блокировки не вызывает ошибки, это происходит только в том случае, если телефон разблокирован; независимо от того, действительно ли мое приложение открыто

полный исключение:

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)

на моем тестовом устройстве работает Android 8.0, project min API-21, а целевой API-27. API устройства-26.

3 ответов


вам нужно использовать NotificationChannel для Android O API 26 и выше, иначе вы получите ошибку, которую вы испытали. См. следующее утверждение из документов Android -создание и управление каналами уведомление:

начиная с Android 8.0 (уровень API 26), все уведомления должны быть назначены каналу.

вот выдержка (возьмите из нее то, что вам нужно) из метода, который я использую для создания наших медиа-уведомлений. Вы можно увидеть, что есть проверка для устройств Android O с определенным методом для обработки этого случая:

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())
}

в своем onStop() обратный вызов, вам нужно позвонить stopSelf() в рамках сервиса. Тогда, когда ваша служба onDestroy() метод называется вам нужно очистить несколько вещей (как относится к вашему случаю) следующим образом:

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)
}

Я не включенными подробно на некоторых из вышеперечисленных методов, но имена методов должны быть комментарии - дайте мне знать, если я могу включить более подробно. Некоторые из они могут быть излишними, но в вашем случае могут решить проблему.

Я уверен, что это решит вашу проблему. Если нет, у меня есть еще несколько идей.


просто потратил слишком много времени на это. Я не уверен, что это то, что вы испытываете, но в моем случае я продолжал получать это исключение, потому что мой NOTIFICATION_ID был 0 ... Использование любого другого значения, похоже, исправляет это.- _ -


у меня была такая же проблема. Проблему с помощью PendingIntent.getForegroundService() в элементах уведомлений нажмите, чтобы обновить службу мультимедиа. Используя только PendingIntent.getService решил проблему для меня.