Hintergrundprozesse können speicher- und akkuintensiv sein. So kann beispielsweise ein impliziter Broadcast viele Hintergrundprozesse starten, die sich für den Empfang registriert haben, auch wenn diese Prozesse nicht viel Arbeit verrichten. Dies kann sich erheblich auf die Geräteleistung und die Nutzerfreundlichkeit auswirken.
Um dieses Problem zu beheben, gelten in Android 7.0 (API-Level 24) die folgenden Einschränkungen:
- Apps, die auf Android 7.0 (API-Level 24) und höher ausgerichtet sind, empfangen keine
CONNECTIVITY_ACTION
-Broadcasts, wenn sie ihren Broadcast-Receiver im Manifest deklarieren. Apps erhalten weiterhinCONNECTIVITY_ACTION
-Broadcasts, wenn sie ihreBroadcastReceiver
beiContext.registerReceiver()
registrieren und dieser Kontext weiterhin gültig ist. - Apps können keine
ACTION_NEW_PICTURE
- oderACTION_NEW_VIDEO
-Broadcasts senden oder empfangen. Diese Optimierung betrifft alle Apps, nicht nur solche, die auf Android 7.0 (API-Level 24) ausgerichtet sind.
Wenn Ihre App einen dieser Intents verwendet, sollten Sie die Abhängigkeiten davon so schnell wie möglich entfernen, damit Sie Geräte mit Android 7.0 oder höher richtig ansprechen können. Das Android-Framework bietet mehrere Lösungen, um die Notwendigkeit dieser impliziten Broadcasts zu verringern. Beispielsweise bieten JobScheduler
und der neue WorkManager robuste Mechanismen zum Planen von Netzwerkoperationen, wenn bestimmte Bedingungen erfüllt sind, z. B. eine Verbindung zu einem Netzwerk mit unbegrenztem Datenvolumen. Sie können jetzt auch JobScheduler
verwenden, um auf Änderungen an Inhaltsanbietern zu reagieren. JobInfo
-Objekte kapseln die Parameter, die JobScheduler
zum Planen Ihres Jobs verwendet. Wenn die Bedingungen des Jobs erfüllt sind, führt das System diesen Job auf dem JobService
Ihrer App aus.
Auf dieser Seite erfahren Sie, wie Sie alternative Methoden wie JobScheduler
verwenden können, um Ihre App an diese neuen Einschränkungen anzupassen.
Von Nutzern initiierte Einschränkungen
Auf der Seite Akkunutzung in den Systemeinstellungen kann der Nutzer zwischen den folgenden Optionen wählen:
- Uneingeschränkt:Alle Hintergrundarbeiten zulassen. Dadurch kann sich der Akkuverbrauch erhöhen.
- Optimiert (Standard): Die Fähigkeit einer App, Hintergrundaufgaben auszuführen, wird basierend darauf optimiert, wie der Nutzer mit der App interagiert.
- Eingeschränkt:Die Ausführung einer App im Hintergrund wird vollständig verhindert. Apps funktionieren möglicherweise nicht wie erwartet.
Wenn eine App einige der in Android Vitals beschriebenen schlechten Verhaltensweisen aufweist, fordert das System den Nutzer möglicherweise auf, den Zugriff dieser App auf Systemressourcen einzuschränken.
Wenn das System feststellt, dass eine App übermäßig viele Ressourcen verbraucht, wird der Nutzer benachrichtigt und erhält die Möglichkeit, die Aktionen der App einzuschränken. Verhaltensweisen, die zur Anzeige der Benachrichtigung führen können:
- Übermäßige Wakelocks: 1 Teil-Wakelock wird eine Stunde lang gehalten, wenn das Display ausgeschaltet ist.
- Zu viele Hintergrunddienste: Wenn die App auf API-Levels unter 26 ausgerichtet ist und zu viele Hintergrunddienste hat
Die genauen Beschränkungen werden vom Gerätehersteller festgelegt. In AOSP-Builds mit Android 9 (API‑Level 28) oder höher unterliegen Apps, die im Hintergrund ausgeführt werden und sich im Status „eingeschränkt“ befinden, beispielsweise den 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 Broadcasts BOOT_COMPLETED
oder LOCKED_BOOT_COMPLETED
erst, wenn die App aus anderen Gründen gestartet wird.
Die spezifischen Einschränkungen sind unter Einschränkungen der Energieverwaltung aufgeführt.
Einschränkungen beim Empfang von Broadcasts zur Netzwerkaktivität
Apps, die auf Android 7.0 (API-Level 24) ausgerichtet sind, empfangen 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 kann ein Problem für Apps sein, die auf Netzwerkänderungen reagieren oder Bulk-Netzwerkaktivitäten ausführen möchten, wenn das Gerät mit einem Netzwerk mit unbegrenztem Datenvolumen verbunden wird. Es gibt bereits mehrere Lösungen, um diese Einschränkung zu umgehen. Welche die richtige ist, hängt davon ab, was Sie mit Ihrer App erreichen möchten.
Hinweis:Eine mit Context.registerReceiver()
registrierte BroadcastReceiver
empfängt diese Broadcasts weiterhin, während die App ausgeführt wird.
Netzwerkjobs über Verbindungen ohne Volumenzähler planen
Wenn Sie die Klasse JobInfo.Builder
verwenden, 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 ein Dienst so geplant, dass er ausgeführt wird, wenn das Gerät mit einem Netzwerk ohne Volumenbegrenzung verbunden ist und geladen wird:
Kotlin
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) }
Java
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, erhält Ihre App einen Callback, um die Methode onStartJob()
im angegebenen JobService.class
auszuführen. Weitere Beispiele für die Implementierung von JobScheduler
finden Sie in der JobScheduler-Beispiel-App.
WorkManager ist eine neue Alternative zu JobScheduler. Mit dieser API können Sie Hintergrundaufgaben planen, die garantiert abgeschlossen werden müssen, unabhängig davon, ob der App-Prozess ausgeführt wird oder nicht. WorkManager wählt die geeignete Methode zum Ausführen der Arbeit aus (entweder direkt in einem Thread in Ihrem App-Prozess oder mit JobScheduler, FirebaseJobDispatcher oder AlarmManager). Die Auswahl hängt von Faktoren wie der API-Ebene des Geräts ab. Außerdem sind für WorkManager keine Play-Dienste erforderlich und es bietet mehrere erweiterte Funktionen, z. B. das Verketten von Aufgaben oder das Prüfen des Status einer Aufgabe. Weitere Informationen finden Sie unter WorkManager.
Netzwerkverbindung während der Ausführung der App überwachen
Apps, die ausgeführt werden, können weiterhin mit einem registrierten BroadcastReceiver
auf CONNECTIVITY_CHANGE
warten. Die ConnectivityManager
API bietet jedoch eine robustere Methode, um einen Callback nur anzufordern, wenn bestimmte Netzwerkbedingungen erfüllt sind.
NetworkRequest
-Objekte definieren die Parameter des Netzwerk-Callbacks in Bezug auf NetworkCapabilities
. Sie erstellen NetworkRequest
-Objekte mit der Klasse NetworkRequest.Builder
. registerNetworkCallback()
übergibt das NetworkRequest
-Objekt dann 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 beendet wird oder unregisterNetworkCallback()
aufgerufen wird.
Einschränkungen beim Empfang von Bild- und Videosendungen
In Android 7.0 (API-Level 24) können Apps keine ACTION_NEW_PICTURE
- oder ACTION_NEW_VIDEO
-Broadcasts senden oder empfangen. Diese Einschränkung trägt dazu bei, 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) erweitert JobInfo
und JobParameters
, um eine alternative Lösung zu bieten.
Jobs bei Änderungen des Inhalts-URI auslösen
Um Jobs bei Änderungen des Inhalts-URI auszulösen, wird die JobInfo
API in Android 7.0 (API-Level 24) um die folgenden Methoden erweitert:
-
JobInfo.TriggerContentUri()
- Kapselt Parameter, die zum Auslösen eines Jobs bei Änderungen des Content-URI erforderlich sind.
-
JobInfo.Builder.addTriggerContentUri()
-
Übergibt ein
TriggerContentUri
-Objekt anJobInfo
. EinContentObserver
überwacht den URI des eingeschlossenen Inhalts. Wenn einem Job mehrereTriggerContentUri
-Objekte zugeordnet sind, stellt das System einen Callback bereit, auch wenn nur eine Änderung an einem der Inhalts-URIs gemeldet wird. -
Fügen Sie das Flag
TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS
hinzu, um den Job auszulösen, wenn sich untergeordnete Elemente des angegebenen URI ändern. Dieses Flag entspricht dem ParameternotifyForDescendants
, der anregisterContentObserver()
übergeben wird.
Hinweis:TriggerContentUri()
kann nicht in Kombination mit setPeriodic()
oder setPersisted()
verwendet werden. Wenn Sie kontinuierlich nach Inhaltsänderungen suchen möchten, planen Sie einen neuen JobInfo
, bevor die JobService
der App den letzten Callback verarbeitet hat.
Im folgenden Beispielcode wird ein Job geplant, der ausgelöst wird, wenn das System eine Änderung am Inhalts-URI MEDIA_URI
meldet:
Kotlin
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) }
Java
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 Ihre App einen Callback und ein JobParameters
-Objekt wird an die onStartJob()
-Methode in MediaContentJob.class
übergeben.
Ermitteln, welche Inhaltsbehörden einen Job ausgelöst haben
In Android 7.0 (API-Level 24) wird JobParameters
erweitert, damit Ihre App nützliche Informationen dazu erhält, welche Content-Authorities und ‑URIs den Job ausgelöst haben:
-
Uri[] getTriggeredContentUris()
-
Gibt ein Array von URIs zurück, die den Job ausgelöst haben. Dieser Wert ist
null
, wenn entweder keine URIs den Job ausgelöst haben (z. B. weil der Job aufgrund einer Frist oder aus einem anderen Grund ausgelöst wurde) oder die Anzahl der geänderten URIs größer als 50 ist. -
String[] getTriggeredContentAuthorities()
-
Gibt ein String-Array mit den Inhaltsberechtigungen zurück, die den Job ausgelöst haben.
Wenn das zurückgegebene Array nicht
null
ist, verwenden SiegetTriggeredContentUris()
, um die Details der geänderten URIs abzurufen.
Im folgenden Beispielcode wird die Methode JobService.onStartJob()
überschrieben und die Inhaltsberechtigungen und URIs aufgezeichnet, die den Job ausgelöst haben:
Kotlin
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 }
Java
@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 für Geräte mit wenig Arbeitsspeicher oder für Situationen mit wenig Arbeitsspeicher optimieren, können Sie die Leistung und Nutzerfreundlichkeit verbessern. Wenn Sie Abhängigkeiten von Hintergrunddiensten und im Manifest registrierten impliziten Übertragungsempfängern entfernen, kann Ihre App auf solchen Geräten besser ausgeführt werden. In Android 7.0 (API-Level 24) wurden Maßnahmen ergriffen, um einige dieser Probleme zu reduzieren. Es wird jedoch empfohlen, Ihre App so zu optimieren, dass sie ohne diese Hintergrundprozesse ausgeführt wird.
Die folgenden Android Debug Bridge (ADB)-Befehle können Ihnen helfen, das App-Verhalten zu testen, wenn Hintergrundprozesse deaktiviert sind:
- Wenn Sie Bedingungen simulieren möchten, unter denen implizite Broadcasts und Hintergrunddienste nicht verfügbar sind, geben Sie den folgenden Befehl ein:
-
$ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND ignore
- Geben Sie den folgenden Befehl ein, um implizite Broadcasts und Hintergrunddienste wieder zu aktivieren:
-
$ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND allow
- Sie können simulieren, dass der Nutzer Ihre App in den Status „eingeschränkt“ für die Akkunutzung im Hintergrund versetzt. Diese Einstellung verhindert, dass Ihre App im Hintergrund ausgeführt werden kann. Führen Sie dazu den folgenden Befehl in einem Terminalfenster aus:
-
$ adb shell cmd appops set <PACKAGE_NAME> RUN_ANY_IN_BACKGROUND deny