07. September 2017 Technologie

Android-Hintergrunddienste


Einschränkungen in Android Oreo durch die Background Execution Limits und Wege für App-Entwickler damit umzugehen

Smarte Apps für Kunden aus der Automobilbranche oder der Industrie – damit befasst sich das App-Entwicklungsteam bei in-tech. Das Spektrum reicht von der Maschinensteuerung via Smartphone übers mobile Bezahlen bis hin zur Musiksteuerung im Auto. Um dabei die neusten Technologien einsetzen und den Kunden die beste Lösung anbieten zu können, setzten sich die App-Entwickler bei in-tech immer wieder mit neuesten Systemen und Versionen auseinander, in diesem Fall mit Android Oreo.

Längere Akkulaufzeit und eine flüssigere Bedienung verspricht sich Google von Einschränkungen in Android 8, die insbesondere Hintergrunddienste betreffen. Damit wird der unter Android 7 begonnen Weg konsequent fortgeführt, Möglichkeiten für Entwickler einzuschränken, die sich negativ auf die Leistung des Geräts und auf die Batterielaufzeit auswirken können.

Der Fokus der Änderungen in Android 7 lag darauf zu verhindern, dass bei bestimmten Ereignissen eine Vielzahl von zunächst inaktiven Apps gleichzeitig in Aktion treten, das System überlasten und so die Bedienung des Geräts stören. Um solche Situationen zu vermeiden, wurden sowohl das Senden als auch der Empfang bestimmter Broadcasts eingeschränkt. Betroffen hiervon sind die Broadcasts CONNECTIVITY_ACTION, ACTION_NEW_PICTURE und ACTION_NEW_VIDEO.[1]

Mit Android 8 werden Broadcasts weiter eingeschränkt. Außerdem werden Hintergrunddienste und die Häufigkeit von Positionsabfragen durch Hintergrunddienste limitiert.

Hintergrunddienste

Die Einschränkungen von Hintergrunddiensten betreffen lediglich Apps, die Android 8 als Zielplattform nutzen (targetSDK = 26) und die sich im Hintergrund befinden. Eine App befindet sich im Hintergrund, wenn sie weder sichtbar ist, noch einen Vordergrunddienst laufen lässt oder eine andere App im Vordergrund mit ihr kommuniziert. Sollte eine App in den Hintergrund geraten, kann das System ihre Hintergrunddienste nach einigen Minuten stoppen.

Um sicher zu gehen, dass eine App auch im Hintergrund notwendige Aufgaben verrichten kann, kann man, wo dies sinnvoll ist, statt Hintergrunddiensten Vordergrunddienste verwenden. Eine andere Möglichkeit ist es, den Android JobScheduler zu nutzen, der mit Android 5 (API-Level 21) eingeführt wurde. Dem JobScheduler können Aufgaben übergeben werden, die entweder einmalig oder periodisch vom System abgearbeitet werden. Auch eine gegebenenfalls notwendige Form der Netzwerkverbindung kann angegeben werden, so dass es möglich ist, beispielsweise eine Aufgabe nur zu starten, wenn eine WLAN-Verbindung verfügbar ist. Als zusätzliche Bedingung kann angegeben werden, dass das Gerät zum Zeitpunkt der Ausführung ansonsten ungenutzt sein muss. Sollte es nicht möglich sein, eine Aufgabe erfolgreich auszuführen, kann der JobScheduler die Aufgabe später erneut starten. Dabei ist es auch möglich, die Zeiten zwischen den Ausführungsversuchen exponentiell oder linear ansteigen zu lassen.

Apps, die auch Systeme mit einem API-Level unter 21 unterstützen müssen, können nicht auf den JobScheduler zurückgreifen. Stattdessen kann der Firebase JobDispatcher[2] oder die Android-Job-Bibliothek von Evernote[3] genutzt werden. Der Firebase JobDispatcher kann auf System ab API-Level 9 (Android 2.3) eingesetzt werden, setzt allerdings die Google Play Services voraus. Die Android-Job-Bibliothek von Evernote kann ab API-Level 14 (Android 4.0) genutzt werden und benötigt keine Google Play Services. Apps, die Evernotes Bibliothek nutzen, laufen also auch auf Geräten mit Custom-ROMs, die oft auf die Google Play Services verzichten und auf Amazon Fire-Hardware. Beide Bibliotheken stehen unter der Apache License 2.0, was den Einsatz sowohl in freier als auch in proprietärer Software erlaubt.

Positionsabfragen in Hintergrunddiensten

Ein häufiger Kritikpunkt von Nutzern ist oft der hohe Batterieverbrauch von Apps als Folge von häufigen Positionsabfragen per GPS. Ab Android 8 können Apps im Hintergrund die Position nicht mehr so häufig abfragen, wie dies bisher der Fall war. Apps im Vordergrund verhalten sich weiterhin wie gewohnt.

Eine App im Hintergrund erhält nur noch ein paarmal pro Stunde Positionsupdates, auch wenn die App sie häufiger angefordert hat. Dies betrifft alle Apps, die auf Geräten mit Android 8 laufen, nicht nur Apps, die speziell für Android 8 erstellt wurden. Es ist daher empfehlenswert, auch das Verhalten älterer Apps unter Android 8 zu überprüfen, um eventuellen Nutzerbeschwerden zuvor zu kommen.

Um auch im Hintergrund die Position weiterhin häufiger als ein paarmal pro Stunde zu erhalten, kann man statt eines Hintergrunddienstes einen Vordergrunddienst benutzen. Dies hat für Nutzer den Vorteil, dass der Vordergrundservice durch eine Notification sichtbar ist und beendet werden kann, wenn er nicht mehr benötigt wird. Eine weitere Alternative ist die Nutzung der GeofencingApi der Google Play Services. Mit ihr ist es möglich, eine Benachrichtigung vom System anzufordern, wenn das Gerät in ein vorher bestimmtes Gebiet bewegt wird oder es verlässt.

Erhält die App im Hintergrund lediglich passiv Positionsdaten, indem sie beim LocationManager einen LocationProvider mit dem Provider-Namen PASSIVE_PROVIDER anfordert, ändert sich auch mit Android 8 nichts am Verhalten. Allerdings erhält die App im Hintergrund dann auch nur Positionsdaten, wenn eine andere App im Vordergrund sich für den Empfang von Positionsdaten beim LocationProvider registriert hat.

Broadcasts

Wie die Änderungen, die das Verhalten der Hintergrunddienste anbelangen, betreffen die Änderungen bezüglich der Broadcasts ebenfalls lediglich Apps, die Android 8 (API-Level 26) als Zielplattform benutzten.

Ab Android 8 können Apps keine impliziten Broadcasts im Manifest mehr registrieren. Implizite Broadcasts sind relativ unspezifische Nachrichten, wie zum Beispiel ACTION_BATTERY_CHANGED. Dieser Broadcast weist lediglich darauf hin, dass sich der Batteriestatus geändert hat, aber nicht, welche Änderung genau stattgefunden hat. Explizite Broadcasts sind genauer darin, was sie beschreiben, wie zum Beispiel ACTION_BATTERY_LOW. Ein Broadcast dieses Typs weist darauf hin, dass die Batterie einen niedrigen Ladezustand erreicht hat. Eine App kann darauf sofort reagieren, ohne weitere Anfragen durchführen zu müssen. Explizite Broadcasts können weiterhin auch im Manifest registriert werden. Implizite Broadcasts müssen von der App mittels Context.registerReceiver() während der Laufzeit registriert werden.

Welche Broadcasts zu den expliziten Broadcasts zählen und welche implizite Broadcasts sind, ist leider nur teilweise aus der Android-Dokumentation ersichtlich. Um die Unübersichtlichkeit noch zu erhöhen, gibt es noch zahlreiche Ausnahmen, die im API Guide beschrieben sind.[4]

Fazit

Auch wenn die Änderungen in Android 8 für Entwickler einen gewissen Aufwand bedeuten, dürften die notwendigen Anpassungen in den meisten Fällen überschaubar sein. Da in den meisten Fällen bereits Alternativen zum bisherigen Vorgehen bestehen, lohnt es sich nicht, die Änderungen auf die lange Bank zu schieben. Zwar wird sich im Verhalten der Apps nicht viel für die Nutzer unmittelbar Ersichtliches ändern, insgesamt werden die Einschränkungen für die Entwickler aber hoffentlich zu einer Verbesserung der Batterielaufzeit und einer flüssigeren Oberfläche von Android-Geräten mit weniger Rucklern führen. Außerdem kann man als Entwickler bei dieser Gelegenheit die Notwendigkeit der Hintergrundaktionen von Apps überdenken, ausgetretene Pfade verlassen und ein Ressourcenschonenderes Verhalten der eigenen Apps anstreben.

 

Weitere Informationen:

https://developer.android.com/about/versions/oreo/background.html

https://developer.android.com/about/versions/oreo/background-location-limits.html

[1] Weitere Informationen zu den Änderungen in Android 7: https://developer.android.com/topic/performance/background-optimization.html und https://www.youtube.com/watch?v=vBjTXKpaFj8

[2] https://github.com/firebase/firebase-jobdispatcher-android

[3] https://github.com/evernote/android-job

[4] https://developer.android.com/guide/components/broadcast-exceptions.html