it-swarm.com.de

Android 8.0: Java.lang.IllegalStateException: Dienst darf nicht gestartet werden

Beim Start der Anwendung startet die Anwendung den Dienst, der eine Netzwerkaufgabe ausführen soll ..__ Nach dem Ansteuern der API-Stufe 26 kann meine Anwendung den Dienst unter Android 8.0 nicht im Hintergrund starten. 

Verursacht durch: Java.lang.IllegalStateException: Nicht zulässig Dienstabsicht { cmp = mein.app.tt/com.my.service }: Die App befindet sich im Hintergrund. UidRecord {90372b1 u0a136 CEM-Leerlaufprozeduren: 1 seq (0,0,0)}

wie ich es verstehe, bezogen sich dies auf: Hintergrundausführungsgrenzen

Die startService () -Methode löst jetzt eine IllegalStateException aus, wenn eine App-Targeting auf Android 8.0 versucht, diese Methode in einer Situation zu verwenden, in der Es ist nicht erlaubt, Hintergrunddienste zu erstellen.

"in einer Situation, in der es nicht erlaubt ist" - was bedeutet es eigentlich? Und wie man es repariert. Ich möchte meinen Dienst nicht als "Vordergrund" festlegen

217
phnmnn

Die zulässigen Situationen sind eine temporäre Whitelist, bei der sich der Hintergrunddienst wie vor Android O verhält.

Unter bestimmten Umständen wird eine Hintergrund-App für einige Minuten in eine temporäre Whitelist aufgenommen. Während sich eine App auf der Whitelist befindet, können Dienste ohne Einschränkung gestartet werden, und die Hintergrunddienste dürfen ausgeführt werden. Eine App wird auf der Whitelist platziert, wenn sie eine für den Benutzer sichtbare Aufgabe bearbeitet, z.

  • Verwalten einer Firebase Cloud Messaging-Nachricht (FCM) mit hoher Priorität.
  • Empfangen einer Sendung, z. B. einer SMS/MMS-Nachricht.
  • Ausführen eines PendingIntent aus einer Benachrichtigung.
  • Das Starten eines VpnService, bevor sich die VPN-App in den Vordergrund rückt.

Quelle: https://developer.Android.com/about/versions/oreo/background.html

Wenn also Ihr Hintergrunddienst die Voraussetzungen für die Whitelist nicht erfüllt, müssen Sie den neuen JobScheduler verwenden. Es ist im Grunde dasselbe wie ein Hintergrunddienst, aber es wird regelmäßig aufgerufen, anstatt ständig im Hintergrund ausgeführt zu werden.

Wenn Sie einen IntentService verwenden, können Sie zu einem JobIntentService wechseln. Siehe @ kosevs Antwort unten .

125
Murat Karagöz

Ich habe eine Lösung. Für Geräte vor Version 8.0 müssen Sie nur startService() verwenden, für Geräte nach 7.0 jedoch müssen Sie startForgroundService() verwenden. Hier ist ein Beispiel für Code zum Starten des Dienstes.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        context.startForegroundService(new Intent(context, ServedService.class));
    } else {
        context.startService(new Intent(context, ServedService.class));
    }

Bitte fügen Sie in der Serviceklasse den folgenden Code für die Benachrichtigung hinzu:

@Override
public void onCreate() {
    super.onCreate();
    startForeground(1,new Notification());
}

Wo O ist Android-Version 26.

Hoffe, es wird gelöst IllegalArgumentException

140
Sagar Kacha

Am besten verwenden Sie JobIntentService , das den neuen JobScheduler für Oreo oder die alten Dienste verwendet, falls diese nicht verfügbar sind.

Erklären Sie in Ihrem Manifest:

<service Android:name=".YourService"
         Android:permission="Android.permission.BIND_JOB_SERVICE"/>

Und in Ihrem Service müssen Sie onHandleIntent durch onHandleWork ersetzen:

public class YourService extends JobIntentService {

    public static final int JOB_ID = 1;

    public static void enqueueWork(Context context, Intent work) {
        enqueueWork(context, YourService.class, JOB_ID, work);
    }

    @Override
    protected void onHandleWork(@NonNull Intent intent) {
        // your code
    }

}

Dann starten Sie Ihren Service mit:

YourService.enqueueWork(context, new Intent());
45
kosev

Wenn der Dienst in einem Hintergrundthread ausgeführt wird, indem Sie IntentService erweitern, können Sie IntentService durch JobIntentService ersetzen, die als Teil der Android Support Library bereitgestellt wird

Der Vorteil der Verwendung von JobIntentService besteht darin, dass es sich bei ohnehin O-Geräten als IntentService verhält und bei O und höher als Job ausgegeben wird

JobScheduler kann auch für periodische/On-Demand-Jobs verwendet werden. Stellen Sie jedoch sicher, dass Sie mit der Abwärtskompatibilität umgehen, da die JobScheduler-API nur über die API 21 verfügbar ist

26
Harini S

Ja, das liegt daran, dass Sie auf API 26 keine Dienste mehr im Hintergrund starten können. Sie können ForegroundService über API 26 starten.

Sie müssen verwenden 

ContextCompat.startForegroundService(...)

und eine Benachrichtigung während der Verarbeitung des Lecks.

11
P.K

Aus den firebase-Versionshinweisen wird angegeben, dass die Unterstützung für Android O erstmals in 10.2.1 veröffentlicht wurde (obwohl ich die neueste Version empfehlen würde).

bitte fügen Sie neue Abhängigkeiten für Firebase-Nachrichten für Android O hinzu

compile 'com.google.firebase:firebase-messaging:11.6.2'

aktualisieren Sie bei Bedarf Google Play-Dienste und Google-Repositorys.

4
Dhaval Jivani

Wie @kosev in seiner Antwort sagte, können Sie JobIntentService verwenden. Aber ich benutze eine alternative Lösung - ich fange IllegalStateException ab und starte den Dienst als Vordergrund. Zum Beispiel startet diese Funktion meinen Dienst:

@JvmStatic
protected fun startService(intentAction: String, serviceType: Class<*>, intentExtraSetup: (Intent) -> Unit) {
    val context = App.context
    val intent = Intent(context, serviceType)
    intent.action = intentAction
    intentExtraSetup(intent)
    intent.putExtra(NEED_FOREGROUND_KEY, false)

    try {
        context.startService(intent)
    }
    catch (ex: IllegalStateException) {
        intent.putExtra(NEED_FOREGROUND_KEY, true)
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            context.startForegroundService(intent)
        }
        else {
            context.startService(intent)
        }
    }
}

und wenn ich Intent verarbeite, mache ich so etwas:

override fun onHandleIntent(intent: Intent?) {
    val needToMoveToForeground = intent?.getBooleanExtra(NEED_FOREGROUND_KEY, false) ?: false
    if(needToMoveToForeground) {
        val notification = notificationService.createSyncServiceNotification()
        startForeground(notification.second, notification.first)

        isInForeground = true
    }

    intent?.let {
        getTask(it)?.process()
    }
}
3
Alex Shevelev

Ich sehe viele Antworten, die nur die Verwendung eines ForegroundService empfehlen. Um einen ForegroundService verwenden zu können, muss eine Benachrichtigung vorhanden sein. Benutzer werden diese Benachrichtigung sehen. Je nach Situation können sie sich mit Ihrer App ärgern und sie deinstallieren. 

Die einfachste Lösung ist die Verwendung der neuen Architekturkomponente WorkManager. Die Dokumentation finden Sie hier: https://developer.Android.com/topic/libraries/architecture/workmanager/

Sie definieren einfach Ihre Worker-Klasse, die Worker erweitert.

public class CompressWorker extends Worker {

    public CompressWorker(
        @NonNull Context context,
        @NonNull WorkerParameters params) {
        super(context, params);
    }

    @Override
    public Worker.Result doWork() {

        // Do the work here--in this case, compress the stored images.
        // In this example no parameters are passed; the task is
        // assumed to be "compress the whole library."
        myCompress();

        // Indicate success or failure with your return value:
        return Result.SUCCESS;

        // (Returning RETRY tells WorkManager to try this task again
        // later; FAILURE says not to try again.)
    }
}

Dann legen Sie fest, wann Sie es ausführen möchten.

    OneTimeWorkRequest compressionWork = 
        new OneTimeWorkRequest.Builder(CompressWorker.class)
            .build();
    WorkManager.getInstance().enqueue(compressionWork);

Einfach! Es gibt viele Möglichkeiten, Worker zu konfigurieren. Es unterstützt wiederkehrende Jobs und Sie können sogar komplexe Dinge wie Verkettung ausführen, wenn Sie es brauchen. Hoffe das hilft.

2
TALE

wenn Sie die Firebase-Messaging-Push-Benachrichtigung integriert haben, 

Hinzufügen/Aktualisieren von Firebase-Messaging-Abhängigkeiten für Android O (Android 8.0) aufgrund von Background Execution Limits .

compile 'com.google.firebase:firebase-messaging:11.4.0'

aktualisieren Sie bei Bedarf Google Play-Dienste und Google-Repositorys.

Update:

 compile 'com.google.firebase:firebase-messaging:11.4.2'
2

Wenn Sie Ihren Code unter 8.0 ausführen, stürzt die Anwendung ab. Starten Sie also den Dienst im Vordergrund. Wenn unter 8.0, verwenden Sie dies:

Intent serviceIntent = new Intent(context, RingtonePlayingService.class);
context.startService(serviceIntent);

Wenn über oder 8.0, dann verwenden Sie diese: 

Intent serviceIntent = new Intent(context, RingtonePlayingService.class);
ContextCompat.startForegroundService(context, serviceIntent );
2
Faizy

Verwenden Sie startForegroundService() anstelle von startService() Vergessen Sie nicht, startForeground(1,new Notification()); innerhalb von 5 Sekunden nach dem Start des Service zu erstellen.

1
Arpit

Bei einer alternativen Lösung mit JobScheduler kann der Dienst in regelmäßigen Abständen im Hintergrund gestartet werden.

Machen Sie zuerst eine Klasse mit dem Namen til.Java

import Android.app.job.JobInfo;
import Android.app.job.JobScheduler;
import Android.content.ComponentName;
import Android.content.Context;

public class Util {
// schedule the start of the service every 10 - 30 seconds
public static void schedulerJob(Context context) {
    ComponentName serviceComponent = new ComponentName(context,TestJobService.class);
    JobInfo.Builder builder = new JobInfo.Builder(0,serviceComponent);
    builder.setMinimumLatency(1*1000);    // wait at least
    builder.setOverrideDeadline(3*1000);  //delay time
    builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED);  // require unmetered network
    builder.setRequiresCharging(false);  // we don't care if the device is charging or not
    builder.setRequiresDeviceIdle(true); // device should be idle
    System.out.println("(scheduler Job");

    JobScheduler jobScheduler = null;
    if (Android.os.Build.VERSION.SDK_INT >= Android.os.Build.VERSION_CODES.M) {
        jobScheduler = context.getSystemService(JobScheduler.class);
    }
    jobScheduler.schedule(builder.build());
   }
  }

Erstellen Sie dann die JobService-Klasse mit dem Namen TestJobService.Java

import Android.app.job.JobParameters;
import Android.app.job.JobService;
import Android.widget.Toast;

  /**
   * JobService to be scheduled by the JobScheduler.
   * start another service
   */ 
public class TestJobService extends JobService {
@Override
public boolean onStartJob(JobParameters params) {
    Util.schedulerJob(getApplicationContext()); // reschedule the job
    Toast.makeText(this, "Bg Service", Toast.LENGTH_SHORT).show();
    return true;
}

@Override
public boolean onStopJob(JobParameters params) {
    return true;
  }
 }

Nach dieser BroadCast Receiver-Klasse mit dem Namen ServiceReceiver.Java

import Android.content.BroadcastReceiver;
import Android.content.Context;
import Android.content.Intent;

 public class ServiceReceiver extends BroadcastReceiver {
 @Override
public void onReceive(Context context, Intent intent) {
    Util.schedulerJob(context);
 }
}

Update Manifest-Datei mit Service- und Empfängerklassencode

<receiver Android:name=".ServiceReceiver" >
        <intent-filter>
            <action Android:name="Android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
    </receiver>
    <service
        Android:name=".TestJobService"
        Android:label="Word service"
        Android:permission="Android.permission.BIND_JOB_SERVICE" >

    </service>

Verließ das main_intent-Startprogramm mit der mainActivity.Java-Datei, die standardmäßig erstellt wird, ohne Änderung in MainActivity.Java

WOOAAH !! Hintergrunddienst startet ohne Vordergrunddienst

1
Anshul1507

In Oreo wurde Android definiert begrenzt auf Hintergrunddienste .

Um die Benutzererfahrung zu verbessern, erzwingt Android 8.0 (API-Ebene 26) Einschränkungen, was Apps im Hintergrund ausführen können.

Wenn Sie jedoch immer einen Dienst ausführen müssen, können Sie den Vordergrunddienst verwenden.

Hintergrund-Diensteinschränkungen: Während sich eine App im Leerlauf befindet, gibt es Grenzen auf die Nutzung von Hintergrunddiensten. Dies gilt nicht für den Vordergrund Dienste, die für den Benutzer auffälliger sind.

So können Sie einen Vordergrunddienst erstellen. Sie müssen ein Benachrichtigung an Benutzer anzeigen, wenn der Dienst ausgeführt wird. Diese Antwort sehen (Es gibt viele andere)

Eine Lösung, wenn -

sie möchten keine Benachrichtigung für Ihren Dienst?

Sie können periodische Aufgaben erstellen, 1. Sie starten Ihren Dienst, 2. Der Dienst erledigt seine Arbeit und 3. stoppt sich selbst. Dadurch wird Ihre App nicht als leere Batterie angesehen.

Sie können periodische Aufgaben mit Alarm Manager , Job Scheduler , Evernote-Jobs oder Work Manager verwenden. 

  • Arbeitsmanager ist am besten Lösung für periodische Aufgaben. Welches wurde mit Android-Architekturkomponente eingeführt. 
  • Im Gegensatz zum Job-Scheduler (nur> 21 API) funktioniert er für alle Versionen.
  • Außerdem beginnt die Arbeit nach einem Doze-Standby-Modus
  • Erstellen Sie ein Android Boot Receiver , um den Dienst nach dem Start des Geräts zu planen.

Ich habe den Dienst ständig mit Work-Manager ausgeführt.

0
Khemraj

Wenn zuvor die Absicht gut funktionierte, während sich die App im Hintergrund befindet, ist dies ab Android 8 nicht mehr der Fall. Bezieht sich nur auf eine Absicht, die einige Verarbeitungsschritte ausführen muss, wenn sich die App im Hintergrund befindet.

Die folgenden Schritte müssen befolgt werden:

  1. In der oben genannten Absicht sollte JobIntentService anstelle von IntentService verwendet werden.
  2. Die Klasse, die JobIntentService erweitert, sollte die - onHandleWork(@NonNull Intent intent)-Methode implementieren und sollte unterhalb der -Methode stehen, die die onHandleWork-Methode aufruft:

    public static void enqueueWork(Context context, Intent work) {
        enqueueWork(context, xyz.class, 123, work);
    }
    
  3. Rufen Sie enqueueWork(Context, intent) von der Klasse auf, in der Ihre Absicht definiert ist.

    Beispielcode:

    Public class A {
    ...
    ...
        Intent intent = new Intent(Context, B.class);
        //startService(intent); 
        B.enqueueWork(Context, intent);
    }
    

Die folgende Klasse hat zuvor die Service-Klasse erweitert

Public Class B extends JobIntentService{
...

    public static void enqueueWork(Context context, Intent work) {
        enqueueWork(context, B.class, JobId, work);
    }

    protected void onHandleWork(@NonNull Intent intent) {
        ...
        ...
    }
}
  1. com.Android.support:support-compat wird für JobIntentService benötigt - ich verwende 26.1.0 V.

  2. Am wichtigsten ist, um sicherzustellen, dass die Firebase-Bibliotheksversion mindestens 10.2.1 ist. Ich hatte Probleme mit 10.2.0 - falls Sie welche haben!

  3. Ihr Manifest sollte die folgende Berechtigung für die Service-Klasse haben:

    service Android:name=".B"
    Android:exported="false"
    Android:permission="Android.permission.BIND_JOB_SERVICE"
    

Hoffe das hilft.

0

Ich denke, der beste Weg, dies zu umgehen, besteht darin, die Build-Version zur Laufzeit zu überprüfen. Abhängig davon kann, wenn sie weniger als API-Level 21 ist, startService () weiter verwendet werden. Wenn es höher ist, sollten Sie einen Job-Scheduler verwenden. Ich denke, Sie können auch den Arbeitsmanager verwenden, aber er befindet sich noch in der Betaphase

0
Meisam