web-dev-qa-db-fra.com

Exception d'exécution Android O avec boot_completed

J'essaie de démarrer un IntentService dans mon récepteur BOOT_COMPLETED, mais en 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 procéder correctement?

28
mars3142

Voici quelques options que j'ai décrites dans n article de blog :

Solution de contournement n ° 1: startForegroundService ()

Votre BroadcastReceiver qui reçoit la diffusion ACTION_BOOT_COMPLETED Pourrait appeler startForegroundService() au lieu de startService() lorsque allumé 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 n'appelle pas réellement startForeground(). Vous disposez d'un laps de temps pour vous déplacer pour appeler startForeground(), "comparable à l'intervalle ANR pour ce faire". Si votre travail est supérieur à une milliseconde mais inférieur à quelques secondes, vous pouvez ignorer l'appel Notification et startForeground(). 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 un Notification brièvement, vous êtes invités à utiliser startForeground() as Android attend de vous, auquel cas vous pouvez faire un travail d'arrière-plan normalement, mais avec une entrée apparaissant dans l'ombre de notification de l'utilisateur.

Solution de contournement n ° 2: goAsync ()

BroadcastReceiver propose goAsync() depuis le niveau d'API 11. Cela permet à votre récepteur de travailler à partir du thread principal de l'application, de sorte que vous pouvez vous débarrasser complètement de IntentService et déplacer votre code dans le BroadcastReceiver. Vous n'avez toujours que le délai d'expiration ANR pour travailler, mais vous ne lierez pas votre thread d'application principal. C'est mieux que la première solution de contournement, dans la mesure où il a la même limitation de temps mais évite l'erreur désagréable. Cependant, cela nécessite une certaine quantité de retouches.

Solution de contournement n ° 3: JobScheduler

Si votre travail prend plus de quelques secondes et vous voulez éviter le Notification, vous pouvez modifier votre code pour implémenter un JobService et travailler avec JobScheduler. Cela a l'avantage supplémentaire de ne vous donner le contrôle que lorsque d'autres critères sont remplis (par exemple, il existe une connexion Internet utilisable). Cependant, non seulement cela nécessite une réécriture, mais JobScheduler n'est disponible que sur Android 5.0+, donc si votre minSdkVersion est inférieur à 21, vous besoin d'une autre solution sur les anciens appareils.

[~ # ~] mise à jour [~ # ~] : Eugen Pechanec a souligné JobIntentService , qui est un mashup JobService/IntentService intéressant.

52
CommonsWare

Vous voudrez peut-être vérifier la section suivante de la documentation sur les changements de comportement Android O --- https://developer.Android.com/preview/features/background.html#services

Il limite désormais le moment où l'application est en mesure de démarrer les services d'arrière-plan.

1
Ryan