Voici quelques options que j'ai décrites dans un article de blog :
Palliatif n°1 : startForegroundService()
Votre BroadcastReceiver
qui reçoit le ACTION_BOOT_COMPLETED
diffuser pourrait appeler startForegroundService()
au lieu de startService()
sous 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);
}
}
}
Notez que cela fonctionne, dans une certaine mesure, même si votre service ne fait pas réellement jamais appelé startForeground()
. On vous donne une fenêtre de temps pour vous déplacer d'appeler startForeground()
"comparable à l'intervalle ANR pour le faire". Si votre travail est plus long qu'une milliseconde mais moins de quelques secondes, vous pourriez sauter le Notification
et le startForeground()
appel. Cependant, vous obtiendrez une erreur dans 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)
Bien sûr, si cela ne vous dérange pas d'avoir une Notification
en bref, vous êtes invités à utiliser startForeground()
comme Android l'attend de vous, auquel cas vous pouvez travail en arrière-plan normalement, mais avec une entrée apparaissant dans l'écran de notification de l'utilisateur. l'ombre.
Palliatif n°2 : goAsync()
BroadcastReceiver
a offert goAsync()
depuis le niveau 11 de l'API. Cela permet à votre récepteur d'effectuer des travaux en dehors du thread principal de l'application, ce qui vous permet de vous débarrasser du IntentService
entièrement et déplacez votre code dans le BroadcastReceiver
. Vous ne disposez toujours que du délai d'attente ANR pour travailler, mais vous ne bloquerez pas le thread principal de l'application. principale. Cette solution est meilleure que la première, dans la mesure où elle présente la même même limitation de temps mais évite l'erreur désagréable. Cependant, elle nécessite une certaine quantité de travail.
Palliatif n° 3 : JobScheduler
Si votre travail prend plus de quelques secondes et vous voulez éviter le Notification
vous pourriez modifier votre code pour mettre en place un JobService
et travailler avec JobScheduler
. Cela présente l'avantage supplémentaire de ne vous donner contrôle que lorsque d'autres critères sont remplis (par exemple, une connexion Internet utilisable). utilisable). Cependant, non seulement cela nécessite une réécriture, mais JobScheduler
est uniquement disponible sur Android 5.0+, donc si votre minSdkVersion
est inférieur à 21, vous aurez besoin d'une autre solution pour les appareils plus anciens.
UPDATE : Eugen Pechanec a souligné JobIntentService
, qui est une intéressante JobService
/ IntentService
mashup.