Hintergrundprozesse können speicher- und energieintensiv sein. So kann eine implizite Übertragung beispielsweise viele Hintergrundprozesse starten, die sich dafür registriert haben, darauf zu warten, auch wenn diese Prozesse nicht viel Arbeit leisten. Dies kann sich sowohl auf die Geräteleistung als auch auf die Nutzerfreundlichkeit erheblich auswirken.
Um dieses Problem zu beheben, gelten unter Android 7.0 (API-Level 24) die folgenden Einschränkungen:
- Apps, die auf Android 7.0 (API-Level 24) oder höher ausgerichtet sind, erhalten keine
CONNECTIVITY_ACTION
-Broadcasts, wenn sie ihren Broadcast-Empfänger im Manifest deklarieren. Apps werden weiterhinCONNECTIVITY_ACTION
Broadcasts empfangen, wenn sie sich registrierenBroadcastReceiver
mitContext.registerReceiver()
und dieser Kontext ist immer noch gültig. - Apps können keine
ACTION_NEW_PICTURE
- oderACTION_NEW_VIDEO
-Anzeigen senden oder empfangen. Diese Optimierung wirkt sich auf alle Apps aus, nicht nur auf solche, die auf Android 7.0 (API-Level 24) ausgerichtet sind.
Wenn Ihre App einen dieser Intents verwendet, sollten Sie Abhängigkeiten von ihnen entfernen
sodass Sie Geräte mit Android 7.0
oder höher. Das Android-Framework bietet mehrere Lösungen, um den Bedarf an diesen impliziten Übertragungen zu verringern. JobScheduler
und der neue WorkManager bieten beispielsweise robuste Mechanismen zum Planen von Netzwerkaktionen, wenn bestimmte Bedingungen erfüllt sind, z. B. eine Verbindung zu einem unbegrenzten Netzwerk. Sie können jetzt auch JobScheduler
verwenden
um auf Veränderungen
von Contentanbietern zu reagieren. JobInfo
-Objekte umfassen die Parameter, mit denen JobScheduler
Ihren Job plant. Wenn die Bedingungen des Jobs erfüllt sind, führt das System diesen Job auf dem JobService
Ihrer App aus.
Auf dieser Seite lernen Sie, wie Sie alternative Methoden wie
JobScheduler
, um deine App an diese neuen
Einschränkungen.
Vom Nutzer initiierte Einschränkungen
Auf der Seite Akkunutzung in den Systemeinstellungen kann der Nutzer zwischen den folgenden Optionen wählen:
- Uneingeschränkt:Alle Vorgänge im Hintergrund werden zugelassen, die den Akku stärker beanspruchen können.
- Optimiert (Standard): Die Fähigkeit einer App, Hintergrundaktivitäten auszuführen, wird basierend auf der Interaktion des Nutzers mit der App optimiert.
- Eingeschränkt:Verhindert, dass eine App im Hintergrund ausgeführt wird. Apps funktioniert möglicherweise nicht wie erwartet.
Wenn eine App einige der in Android Vitalparameter verwenden, fordert das System den Nutzer möglicherweise auf, Zugriff dieser App auf Systemressourcen.
Wenn das System feststellt, dass eine App zu viele Ressourcen verbraucht, wird der Nutzer benachrichtigt und kann die Aktionen der App einschränken. Folgende Verhaltensweisen können die Benachrichtigung auslösen:
- Übermäßige Wakelocks: 1 Teil-Wakelock, der bei ausgeschaltetem Display eine Stunde lang gehalten wird
- Übermäßige Hintergrunddienste: Wenn die App auf API-Levels unter 26 ausgerichtet ist und übermäßig viele Hintergrunddienste
Die genauen Einschränkungen werden vom Gerätehersteller festgelegt. Beispielsweise gelten für Apps, die im Hintergrund ausgeführt werden und den Status „eingeschränkt“ haben, in AOSP-Builds mit Android 9 (API-Level 28) oder höher die folgenden Einschränkungen:
- Dienste im Vordergrund können nicht gestartet werden
- Vorhandene Dienste im Vordergrund werden aus dem Vordergrund entfernt
- Wecker werden nicht ausgelöst
- Jobs werden nicht ausgeführt
Wenn eine App auf Android 13 (API-Level 33) oder höher ausgerichtet ist und sich im Status „eingeschränkt“ befindet, sendet das System die BOOT_COMPLETED
- oder LOCKED_BOOT_COMPLETED
-Broadcasts erst, wenn die App aus anderen Gründen gestartet wird.
Die spezifischen Einschränkungen sind unter Einschränkungen bei der Energieverwaltung:
Einschränkungen beim Empfang von Übertragungen von Netzwerkaktivitäten
Apps, die auf Android 7.0 (API-Level 24) ausgerichtet sind, erhalten keine CONNECTIVITY_ACTION
-Broadcasts, wenn sie sich in ihrem Manifest für den Empfang registrieren. Prozesse, die von diesem Broadcast abhängen, werden nicht gestartet. Das könnte ein Problem für Apps darstellen, die
um Netzwerkänderungen zu überwachen oder
Bulk-Netzwerkaktivitäten durchzuführen, wenn der
sich das Gerät mit einem kostenlosen Netzwerk verbindet. Verschiedene Lösungen zur Umgehung dieses Problems
bereits im Android-Framework vorhanden, aber die Wahl des richtigen
hängt davon ab, was Sie mit Ihrer App erreichen möchten.
Hinweis: Ein bei Context.registerReceiver()
registrierter BroadcastReceiver
empfängt diese Übertragungen weiterhin, während die App ausgeführt wird.
Netzwerkjobs für nicht getaktete Verbindungen planen
Mit der Klasse JobInfo.Builder
Um das JobInfo
-Objekt zu erstellen, wenden Sie die Methode setRequiredNetworkType()
an und übergeben Sie JobInfo.NETWORK_TYPE_UNMETERED
als Jobparameter. Im folgenden Codebeispiel wird
plant einen Dienst, der ausgeführt wird, wenn das Gerät eine Verbindung zu einem nicht getakteten
Netzwerk und wird aufgeladen:
const val MY_BACKGROUND_JOB = 0 ... fun scheduleJob(context: Context) { val jobScheduler = context.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler val job = JobInfo.Builder( MY_BACKGROUND_JOB, ComponentName(context, MyJobService::class.java) ) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED) .setRequiresCharging(true) .build() jobScheduler.schedule(job) }
public static final int MY_BACKGROUND_JOB = 0; ... public static void scheduleJob(Context context) { JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); JobInfo job = new JobInfo.Builder( MY_BACKGROUND_JOB, new ComponentName(context, MyJobService.class)) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED) .setRequiresCharging(true) .build(); js.schedule(job); }
Wenn die Bedingungen für Ihren Job erfüllt sind, empfängt Ihre Anwendung einen Callback, der ausgeführt werden soll.
die onStartJob()
-Methode im
hat JobService.class
angegeben. Weitere Beispiele für die Implementierung von JobScheduler
findest du in der Beispiel-App "JobScheduler".
Eine neue Alternative zu JobScheduler ist WorkManager, eine API, mit der Sie Hintergrundaufgaben planen können, die garantiert abgeschlossen werden müssen, unabhängig davon, ob der App-Prozess aktiv ist oder nicht. WorkManager wählt den geeigneten Weg für die Ausführung der Arbeit aus (entweder direkt in einem Thread in Ihrem Anwendungsprozess als sowie JobScheduler, FirebaseJobDispatcher oder AlarmManager) auf Grundlage von Faktoren wie dem API-Level des Geräts. Außerdem sind für WorkManager keine Google Play-Dienste erforderlich. Mehrere erweiterte Funktionen wie das Verketten von Aufgaben oder die Überprüfung des Aufgabenstatus Weitere Informationen finden Sie unter WorkManager.
Netzwerkkonnektivität überwachen, während die App ausgeführt wird
Laufende Apps können weiterhin mit einer registrierten BroadcastReceiver
auf CONNECTIVITY_CHANGE
warten. Die ConnectivityManager
API bietet jedoch eine robustere Anfragemethode
ein Callback nur dann, wenn bestimmte Netzwerkbedingungen erfüllt sind.
NetworkRequest
-Objekte definieren die Parameter der
Netzwerk-Callback in Bezug auf NetworkCapabilities
. Ich
NetworkRequest
-Objekte mit der Klasse NetworkRequest.Builder
erstellen registerNetworkCallback()
übergibt dann das NetworkRequest
-Objekt an das System. Wenn die Netzwerkbedingungen erfüllt sind, erhält die App einen Callback, um die in der ConnectivityManager.NetworkCallback
-Klasse definierte onAvailable()
-Methode auszuführen.
Die App empfängt weiterhin Callbacks, bis sie entweder beendet wird oder unregisterNetworkCallback()
aufruft.
Einschränkungen für den Empfang von Bild- und Videoübertragungen
Unter Android 7.0 (API-Level 24) können Apps keine ACTION_NEW_PICTURE
- oder ACTION_NEW_VIDEO
-Broadcasts senden oder empfangen. Diese Einschränkung hilft, die Auswirkungen auf die Leistung und die Nutzerfreundlichkeit zu verringern, wenn mehrere Apps aktiviert werden müssen, um ein neues Bild oder Video zu verarbeiten. Android 7.0 (API-Level 24) bietet eine alternative Lösung, die JobInfo
und JobParameters
erweitert.
Jobs bei Änderungen der Inhalts-URI auslösen
Um Jobs bei Änderungen des Inhalts-URI auszulösen, umfasst Android 7.0 (API-Level 24)
der JobInfo
API mit den folgenden Methoden:
-
JobInfo.TriggerContentUri()
- Enthält Parameter, die erforderlich sind, um einen Job bei Änderungen des Inhalts-URIs auszulösen.
-
JobInfo.Builder.addTriggerContentUri()
-
Übergibt ein
TriggerContentUri
-Objekt anJobInfo
. EinContentObserver
überwacht den URI des gekapselten Inhalts. Wenn einem Job mehrereTriggerContentUri
-Objekte zugeordnet sind, stellt das System ein zurück, auch wenn nur eine Änderung an einem der Inhalts-URIs gemeldet wird. -
Fügen Sie das Flag
TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS
den Job auslösen, wenn sich Nachfolgerelemente des angegebenen URI ändern. Dieses Flag entspricht demnotifyForDescendants
-Parameter, der anregisterContentObserver()
übergeben wurde.
Hinweis: TriggerContentUri()
kann nicht mit setPeriodic()
oder setPersisted()
kombiniert werden. Wenn du kontinuierlich nach Inhaltsänderungen suchen möchtest, plane einen neuen JobInfo
, bevor die JobService
der App die Verarbeitung des letzten Rückrufs abgeschlossen hat.
Mit dem folgenden Beispielcode wird ein Job geplant, der ausgelöst wird, wenn das System
eine Änderung am Inhalts-URI MEDIA_URI
:
const val MY_BACKGROUND_JOB = 0 ... fun scheduleJob(context: Context) { val jobScheduler = context.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler val job = JobInfo.Builder( MY_BACKGROUND_JOB, ComponentName(context, MediaContentJob::class.java) ) .addTriggerContentUri( JobInfo.TriggerContentUri( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS ) ) .build() jobScheduler.schedule(job) }
public static final int MY_BACKGROUND_JOB = 0; ... public static void scheduleJob(Context context) { JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); JobInfo.Builder builder = new JobInfo.Builder( MY_BACKGROUND_JOB, new ComponentName(context, MediaContentJob.class)); builder.addTriggerContentUri( new JobInfo.TriggerContentUri(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS)); js.schedule(builder.build()); }
Wenn das System eine Änderung an den angegebenen Inhalts-URIs meldet, erhält deine App einen Rückruf und ein JobParameters
-Objekt wird an die onStartJob()
-Methode in MediaContentJob.class
übergeben.
Ermitteln, welche Content-Behörden einen Job ausgelöst haben
Unter Android 7.0 (API-Level 24) wird JobParameters
außerdem erweitert, damit Ihre App nützliche Informationen dazu erhält, welche Content-Behörden und URIs den Job ausgelöst haben:
-
Uri[] getTriggeredContentUris()
-
Gibt ein Array von URIs zurück, die den Job ausgelöst haben. Der Wert ist
null
, wenn der Job nicht durch einen URI ausgelöst wurde, beispielsweise aufgrund einer Frist oder aus einem anderen Grund ausgelöst) URIs sind größer als 50. -
String[] getTriggeredContentAuthorities()
-
Gibt ein String-Array mit Inhaltsbehörden zurück, die den Job ausgelöst haben.
Wenn das zurückgegebene Array nicht
null
ist, verwenden SiegetTriggeredContentUris()
um Details zu den geänderten URIs abzurufen.
Der folgende Beispielcode überschreibt die Methode JobService.onStartJob()
und
zeichnet die Inhaltsbehörden und URIs auf, die den Job ausgelöst haben:
override fun onStartJob(params: JobParameters): Boolean { StringBuilder().apply { append("Media content has changed:\n") params.triggeredContentAuthorities?.also { authorities -> append("Authorities: ${authorities.joinToString(", ")}\n") append(params.triggeredContentUris?.joinToString("\n")) } ?: append("(No content)") Log.i(TAG, toString()) } return true }
@Override public boolean onStartJob(JobParameters params) { StringBuilder sb = new StringBuilder(); sb.append("Media content has changed:\n"); if (params.getTriggeredContentAuthorities() != null) { sb.append("Authorities: "); boolean first = true; for (String auth : params.getTriggeredContentAuthorities()) { if (first) { first = false; } else { sb.append(", "); } sb.append(auth); } if (params.getTriggeredContentUris() != null) { for (Uri uri : params.getTriggeredContentUris()) { sb.append("\n"); sb.append(uri); } } } else { sb.append("(No content)"); } Log.i(TAG, sb.toString()); return true; }
App weiter optimieren
Wenn Sie Ihre Apps so optimieren, dass sie auf Geräten mit wenig Arbeitsspeicher oder bei wenig Arbeitsspeicher ausgeführt werden können, lässt sich die Leistung und Nutzerfreundlichkeit verbessern. Wird entfernt Abhängigkeiten von Hintergrunddiensten und Manifest-registrierte implizite Übertragungsempfänger können dazu beitragen, dass Ihre App auf solchen Geräten besser läuft. Unter Android 7.0 (API-Level 24) werden zwar Maßnahmen ergriffen, um einige dieser Probleme zu reduzieren, wir empfehlen Ihnen jedoch, Ihre App so zu optimieren, dass sie ohne diese Hintergrundprozesse ausgeführt wird.
Mit den folgenden Android Debug Bridge (ADB)-Befehlen können Sie das App-Verhalten bei deaktivierten Hintergrundprozessen testen:
- Wenn Sie Bedingungen simulieren möchten, in denen implizite Übertragungen und Hintergrunddienste nicht verfügbar sind, geben Sie den folgenden Befehl ein:
-
$ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND ignore
- Um implizite Broadcasts und Hintergrunddienste wieder zu aktivieren, geben Sie den folgenden Befehl:
-
$ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND allow
- Sie können simulieren, dass der Nutzer Ihre App für die Akkunutzung im Hintergrund in den Status „Eingeschränkt“ versetzt. Mit dieser Einstellung kann Ihre App nicht im Hintergrund ausgeführt werden. Führen Sie dazu den folgenden Befehl in einem Terminalfenster aus:
-
$ adb shell cmd appops set <PACKAGE_NAME> RUN_ANY_IN_BACKGROUND deny