Подтвердить что ты не робот

Исключение времени автономной работы ОС O с boot_completed

Я пытаюсь запустить IntentService в моем приемнике BOOT_COMPLETED, но в Android O (API 26) я получаю:

java.lang.RuntimeException: 
java.lang.IllegalStateException: 
Not allowed to start service Intent { act=intent.action.update cmp=packageName.services.OwnService }: 
app is in background

(Сообщение находится в одной строке, но это упрощает чтение)

Как я могу сделать это правильно?

4b9b3361

Ответ 1

Вот несколько вариантов, которые я описал в сообщении в блоге:

Обходной путь №1: startForegroundService()

Ваш BroadcastReceiver, который получает трансляцию ACTION_BOOT_COMPLETED может вызывать startForegroundService() вместо startService(), когда на Android 8.0 +:

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Build;

public class OnBootReceiver extends BroadcastReceiver {

  @Override
  public void onReceive(Context context, Intent intent) {
    Intent i=new Intent(context, TestIntentService.class);

    if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.O) {
      context.startForegroundService(i);
    }
    else {
      context.startService(i);
    }
  }
}

Обратите внимание, что это работает, в какой-то мере, даже если ваша служба не когда-либо звоните startForeground(). Вам дается окно времени, чтобы обойти на вызов startForeground(), "сопоставимый с интервалом ANR для этого". Если ваша работа длиннее миллисекунды, но менее нескольких секунд, вы можете пропустить вызов Notification и startForeground(). Однако, вы получите сообщение об ошибке в LogCat:

E/AndroidRuntime: FATAL EXCEPTION: main
 Process: com.commonsware.myapplication, PID: 5991
 android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground()
     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1775)
     at android.os.Handler.dispatchMessage(Handler.java:105)
     at android.os.Looper.loop(Looper.java:164)
     at android.app.ActivityThread.main(ActivityThread.java:6541)
     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)

Конечно, если вы не против иметь Notification вкратце, вы можете использовать startForeground(), как ожидает Android, и в этом случае вы можете обычно выполняйте фоновые работы, хотя с записью, отображаемой в уведомлении пользователя оттенок.

Обходной путь №2: goAsync()

BroadcastReceiver предложил goAsync() с уровня API уровня 11. Это позволяет приемник, чтобы выполнить работу с основной прикладной нитью, чтобы вы могли избавиться от IntentService полностью и переместите свой код в BroadcastReceiver. У вас все еще есть ANR время ожидания для работы, но вы не будете связывать свое основное приложение нить. Это лучше, чем первое обходное решение, поскольку оно имеет тот же но избегает неприятной ошибки. Однако это требует некоторой суммы доработки.

Обходной путь №3: JobScheduler

Если ваша работа займет больше нескольких секунд, и вы хотите избежать Notification, вы можете изменить свой код для реализации JobService и работайте с JobScheduler. Это имеет дополнительное преимущество только для вас контроля, когда выполняются другие критерии (например, есть доступный Интернет подключение). Однако для этого требуется не только переписать, но JobScheduler доступен только на Android 5.0+, поэтому, если ваш minSdkVersion меньше 21, вам понадобится другое решение на старых устройствах.

UPDATE: Eugen Pechanec указал JobIntentService, который является интересным JobService/IntentService mashup.

Ответ 2

Возможно, вы захотите проверить следующий раздел документации по изменениям поведения Android O https://developer.android.com/preview/features/background.html#services

Теперь это ограничение, когда приложение может запускать фоновые службы.