Ответ 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.