startForegroundService () не вызывал startForeground (), но сделал - PullRequest
0 голосов
/ 15 мая 2018

У меня есть 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) метод вызывается только из моих MediaSession обратных вызовов:onPlay, onPause и onStop ... очевидно, что действие является предполагаемым действием, которое должно быть выполнено.

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

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

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

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

Дополнительные сведения:

  • Служба не перезапускается частично из-за моей активности «сейчас играет», поскольку выполнение кода никогда не достигает ни одного из его методов.

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

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

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

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

Полное исключение:

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, минимальный API проекта - 21, а целевой API -27. API устройства - 26.

Ответы [ 3 ]

0 голосов
/ 17 мая 2018

Вам необходимо использовать 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)
}

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

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

0 голосов
/ 31 мая 2018

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

0 голосов
/ 16 мая 2018

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

...