28 votes

Exception d'exécution Android O avec boot_completed

J'essaie de lancer un IntentService dans mon récepteur BOOT_COMPLETED, mais dans Android O (API 26) j'obtiens :

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

(Le message est sur une seule ligne, mais de cette façon il est plus facile à lire)

Comment puis-je faire cela de manière correcte ?

52voto

CommonsWare Points 402670

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.

1voto

Ryan Points 1478

Vous pouvez vérifier la section suivante de la documentation sur les modifications du comportement d'Android O https://developer.Android.com/preview/features/background.html#services

Il limite désormais le moment où l'application peut lancer des services en arrière-plan.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X