Hintergrundprozesse können speicher- und energieintensiv sein. Beispielsweise kann ein impliziter Broadcast viele Hintergrundprozesse starten, die registriert sind, um ihn zu überwachen, auch wenn diese Prozesse möglicherweise nicht viel Arbeit leisten. Dies kann erhebliche Auswirkungen auf die Geräteleistung und die Nutzerfreundlichkeit haben.
Um dieses Problem zu beheben, gelten für 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 der Übertragungsempfänger im Manifest deklariert ist. Apps empfangen 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 deine App einen dieser Intents verwendet, solltest du Abhängigkeiten so schnell wie möglich entfernen, damit du Geräte mit Android 7.0 oder höher korrekt ausrichten kannst. Das Android-Framework bietet mehrere Lösungen, um die Notwendigkeit dieser impliziten Broadcasts zu verringern. JobScheduler
und der neue WorkManager bieten beispielsweise robuste Mechanismen zum Planen von Netzwerkvorgängen, wenn bestimmte Bedingungen erfüllt sind, z. B. eine Verbindung zu einem nicht getakteten Netzwerk. Du kannst jetzt auch JobScheduler
verwenden, um auf Änderungen bei Contentanbietern 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 im JobService
Ihrer Anwendung aus.
Auf dieser Seite erfahren Sie, wie Sie Ihre App mit alternativen Methoden wie JobScheduler
an diese neuen Einschränkungen anpassen können.
Vom Nutzer initiierte Einschränkungen
Auf der Seite Akkunutzung in den Systemeinstellungen kann der Nutzer eine der folgenden Optionen auswählen:
- Uneingeschränkt:Alle Vorgänge im Hintergrund werden zugelassen, die den Akku stärker beanspruchen können.
- Optimiert (Standardeinstellung): Hiermit wird die Fähigkeit einer App zum Ausführen von Hintergrundarbeiten optimiert, basierend auf der Interaktion des Nutzers mit der App.
- Eingeschränkt:Verhindert, dass eine App im Hintergrund ausgeführt wird. Apps funktionieren möglicherweise nicht wie erwartet.
Wenn eine App einige der unter Android Vitals beschriebenen schlechten Verhaltensweisen aufweist, fordert das System den Nutzer möglicherweise auf, den Zugriff dieser App auf Systemressourcen zu beschränken.
Wenn das System feststellt, dass eine Anwendung übermäßig viele Ressourcen verbraucht, wird der Nutzer benachrichtigt und ihm die Möglichkeit gegeben, die Aktionen der Anwendung einzuschrä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 verwendet
Die genauen Einschränkungen werden vom Gerätehersteller festgelegt. Bei AOSP-Builds mit Android 9 (API-Level 28) oder höher gelten für im Hintergrund ausgeführte Apps mit dem Status „Eingeschränkt“ beispielsweise die folgenden Einschränkungen:
- Dienste im Vordergrund können nicht gestartet werden
- Vorhandene Dienste im Vordergrund werden aus dem Vordergrund entfernt
- Es werden keine Wecker 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, liefert das System die BOOT_COMPLETED
- oder LOCKED_BOOT_COMPLETED
-Übertragung erst, wenn sie aus anderen Gründen gestartet wird.
Die spezifischen Einschränkungen sind unter Einschränkungen der Energieverwaltung aufgeführt.
Einschränkungen für den Empfang von Netzwerkaktivitäts-Broadcasts
Apps, die auf Android 7.0 (API-Level 24) ausgerichtet sind, empfangen keine CONNECTIVITY_ACTION
-Broadcasts, wenn sie sich für den Empfang in ihrem Manifest registrieren. Von dieser Übertragung abhängige Prozesse werden nicht gestartet. Dies kann zu einem Problem für Apps führen, die Netzwerkänderungen überwachen oder Bulk-Netzwerkaktivitäten ausführen möchten, wenn sich das Gerät mit einem kostenlosen Netzwerk verbindet. Im Android-Framework gibt es bereits mehrere Lösungen zur Umgehung dieser Einschränkung. Die Auswahl der richtigen Lösung hängt jedoch davon ab, was Ihre App erreichen soll.
Hinweis:Eine bei Context.registerReceiver()
registrierte BroadcastReceiver
empfängt diese Broadcasts weiterhin, während die App ausgeführt wird.
Netzwerkjobs für nicht getaktete Verbindungen planen
Wenn Sie die JobInfo.Builder
-Klasse zum Erstellen des JobInfo
-Objekts verwenden, wenden Sie die Methode setRequiredNetworkType()
an und übergeben Sie JobInfo.NETWORK_TYPE_UNMETERED
als Jobparameter. Im folgenden Codebeispiel wird ein Dienst geplant, der ausgeführt wird, wenn das Gerät mit einem kostenlosen Netzwerk verbunden ist und aufgeladen 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, empfängt Ihre Anwendung einen Callback, um die Methode onStartJob()
im angegebenen JobService.class
auszuführen. Weitere Beispiele für die Implementierung von JobScheduler
findest du in der Beispiel-App "JobScheduler".
Eine neue Alternative zu JobScheduler ist WorkManager. Mit dieser API können Sie Hintergrundaufgaben planen, die garantiert abgeschlossen werden müssen, unabhängig davon, ob der Anwendungsprozess gerade stattfindet oder nicht. WorkManager wählt anhand von Faktoren wie dem API-Level des Geräts entweder direkt in einem Thread in Ihrem App-Prozess oder mithilfe von JobScheduler, FirebaseJobDispatcher oder AlarmManager aus, wie die Arbeit ausgeführt werden soll. Außerdem erfordert WorkManager keine Play-Dienste und bietet mehrere erweiterte Funktionen, wie das Verketten von Aufgaben oder das Prüfen des Aufgabenstatus. Weitere Informationen finden Sie unter WorkManager.
Netzwerkkonnektivität überwachen, während die App ausgeführt wird
Aktive Apps können weiterhin mit einer registrierten BroadcastReceiver
auf CONNECTIVITY_CHANGE
warten. Die ConnectivityManager
API bietet jedoch eine robustere Methode, um einen Callback nur dann anzufordern, wenn bestimmte Netzwerkbedingungen erfüllt sind.
NetworkRequest
-Objekte definieren die Parameter des Netzwerk-Callbacks in Bezug auf NetworkCapabilities
. NetworkRequest
-Objekte werden mit der Klasse NetworkRequest.Builder
erstellt. registerNetworkCallback()
übergibt dann das NetworkRequest
-Objekt an das System. Wenn die Netzwerkbedingungen erfüllt sind, empfängt die App einen Callback, um die in ihrer ConnectivityManager.NetworkCallback
-Klasse definierte Methode onAvailable()
auszuführen.
Die App empfängt weiterhin Callbacks, bis sie beendet oder unregisterNetworkCallback()
aufgerufen wird.
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. Durch diese Einschränkung werden die Leistungs- und Nutzerfreundlichkeit verringert, 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
als alternative Lösung.
Jobs bei Änderungen des Inhalts-URI auslösen
Android 7.0 (API-Level 24) erweitert die JobInfo
API um die folgenden Methoden, um Jobs bei Änderungen des Inhalts-URI auszulösen:
-
JobInfo.TriggerContentUri()
- Kapselt Parameter, die zum Auslösen eines Jobs bei Änderungen am Inhalts-URI erforderlich sind.
-
JobInfo.Builder.addTriggerContentUri()
-
Übergibt ein
TriggerContentUri
-Objekt anJobInfo
. EinContentObserver
überwacht den gekapselten Inhalts-URI. Wenn einem Job mehrereTriggerContentUri
-Objekte zugeordnet sind, stellt das System einen Callback bereit, auch wenn nur eine Änderung in einem der Inhalts-URIs gemeldet wird. -
Fügen Sie das Flag
TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS
hinzu, damit der Job ausgelöst wird, wenn sich Nachfolgerelemente des angegebenen URI ändern. Dieses Flag entspricht dem ParameternotifyForDescendants
, der anregisterContentObserver()
übergeben wurde.
Hinweis: TriggerContentUri()
kann nicht in Kombination mit setPeriodic()
oder setPersisted()
verwendet werden. Damit du kontinuierlich nach Inhaltsänderungen Ausschau halten kannst, plane eine neue JobInfo
, bevor die JobService
der App den letzten Callback verarbeitet.
Mit dem 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, empfängt deine App einen Callback und ein JobParameters
-Objekt wird an die Methode onStartJob()
in MediaContentJob.class
übergeben.
Ermitteln, welche Inhaltsbehörden einen Job ausgelöst haben
Android 7.0 (API-Level 24) erweitert außerdem JobParameters
, damit deine App nützliche Informationen darüber erhält, welche Inhaltsbehö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 entweder kein URI den Job ausgelöst hat (z. B. aufgrund einer Frist oder aus einem anderen Grund) oder wenn die Anzahl der geänderten URIs mehr als 50 beträgt. -
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 die Details der URIs abzurufen, die sich geändert haben.
Der folgende Beispielcode überschreibt die Methode JobService.onStartJob()
und zeichnet die Inhaltstellen und URIs auf, 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 du deine Apps für die Ausführung auf Geräten mit wenig Arbeitsspeicher oder bei wenig Arbeitsspeicher optimierst, kannst du Leistung und Nutzerfreundlichkeit verbessern. Wenn du Abhängigkeiten von Hintergrunddiensten und von Manifest-registrierten impliziten Broadcast-Empfängern entfernst, funktioniert deine App möglicherweise besser auf solchen Geräten. Unter Android 7.0 (API-Level 24) werden zwar einige dieser Probleme reduziert, aber es wird empfohlen, deine App so zu optimieren, dass sie vollständig ohne diese Hintergrundprozesse ausgeführt wird.
Mit den folgenden Android Debug Bridge-Befehlen (ADB) können Sie das App-Verhalten bei deaktivierten Hintergrundprozessen testen:
- Geben Sie den folgenden Befehl ein, um Bedingungen zu simulieren, unter denen implizite Broadcasts und Hintergrunddienste nicht verfügbar sind:
-
$ 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
- Du kannst simulieren, dass der Nutzer deine App für die Akkunutzung im Hintergrund in den Status „Eingeschränkt“ 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