Ошибка связанного обслуживания с помощью "Context.startForegroundService() не вызвала ошибку Service.startForeground()"

В настоящее время я работаю над приложением для воспроизведения звука, и я использую запущенную службу для воспроизведения музыки в фоновом режиме. Я начинаю и привязываюсь к службе, используя следующий код.

val intent = Intent(context, MusicService::class.java)
context.startService(intent)
context.bindService(intent, serviceConnection, 0)

Он продвигается на передний план при игре и получает понижение в рейтинге, когда музыка приостанавливается.

// onAudioPlay
service.startForeground(NOTIFY_ID, notification)

// onAudioPause
service.stopForeground(false)

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

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)

Это происходит только в Oreo, и я уже читал об ограничениях фона в Oreo. Но следующие моменты меня обманывают.

  • Эта служба является связанной службой (на которую не распространяются ограничения)
  • Я никогда не использую Context.startForegroundService() для запуска службы (и не хочу ее использовать).
  • Служба не сбрасывается, когда ее снижают с приоритета, это происходит при удалении уведомления.

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

Ответ 1

Чтобы расширить ответ UdeshUk - любое использование MediaButtonReceiver (либо создание ожидающих намерений, либо просто получение намерений мультимедийных кнопок) может привести к тому, что ваш сервис будет вызываться с помощью startForegroundService, поскольку MediaButtonReceiver.onReceive запускает ваш сервис таким образом в Oreo. Я не видел это нигде документально.

Ответ 2

Вы должны вызвать этот метод внутри вашего класса Service onCreate(): ->

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

Ответ 3

Я нашел проблему. В моем уведомлении я установил

setDeleteIntent(MediaButtonReceiver.buildMediaButtonPendingIntent(service, PlaybackStateCompat.ACTION_STOP))

Поэтому, когда пользователь удаляет уведомление, он вызывает startForegroundService(), потому что я вызывал stopForeground() ранее при паузе.

Чтобы преодолеть, я использовал индивидуальное ожидающее намерение и обработал его в onStartCommand() вместо MediaButtonReveiver PendingIntent

Ответ 4

Из документов 8.0 Изменения поведения

Система позволяет приложениям вызывать Context.startForegroundService() даже в то время как приложение находится в фоновом режиме. Однако приложение должно вызвать это службы startForeground() в течение пяти секунд после создается сервис.

Итак, вы должны вызвать startForeground внутри onCreate() для вашей службы.

Ответ 5

Поздно к вечеринке, но, как упоминалось ранее, это MediaButtonReceiver; у него есть этот код:

    @Override
    public void onReceive(Context context, Intent intent) {
        ...
        startForegroundService(context, intent);
        ...
    }

Я использую получатель в связанном сервисе, поэтому я создал класс, который имеет тот же код, что и MediaButtonReceiver, за исключением этой строки. Я заменил его на:

        context.startService(intent);