Hintergrundoptimierung

Hintergrundprozesse können speicher- und akkuintensiv sein. Beispielsweise kann eine implizite Broadcast-Nachricht viele Hintergrundprozesse starten, die sich für den Empfang dieser Nachricht 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 Broadcast-Nachrichten, wenn sie ihren Broadcast-Empfänger im Manifest deklarieren. Apps empfangen weiterhin CONNECTIVITY_ACTION Broadcast-Nachrichten, wenn sie ihren BroadcastReceiver mit Context.registerReceiver() registrieren und dieser Kontext noch gültig ist.
  • Apps können keine ACTION_NEW_PICTURE- oder ACTION_NEW_VIDEO-Broadcast-Nachrichten 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 Abhängigkeiten davon so schnell wie möglich entfernen, damit Sie Geräte mit Android 7.0 oder höher ordnungsgemäß ansprechen können. Das Android-Framework bietet mehrere Lösungen, um die Notwendigkeit dieser impliziten Broadcast-Nachrichten zu verringern. Beispielsweise bieten JobScheduler und der neue WorkManager robuste Mechanismen zum Planen von Netzwerk aktivitäten, wenn bestimmte Bedingungen erfüllt sind, z. B. eine Verbindung zu einem Netzwerk mit Datentarif ohne Mengenbegrenzung. Sie können JobScheduler jetzt auch verwenden, um auf Änderungen an Content-Providern 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 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 Hintergrundaktivitäten zulassen. Dies kann zu einem höheren Akkuverbrauch führen.
  • Optimiert (Standard): Die Möglichkeit einer App, Hintergrundaktivitäten auszuführen, wird basierend darauf optimiert, wie der Nutzer mit der App interagiert.
  • Eingeschränkt: Verhindert vollständig, dass eine App im Hintergrund ausgeführt wird. 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, benachrichtigt es den Nutzer und gibt ihm die Möglichkeit, die Aktionen der App einzuschränken. Verhaltensweisen, die die Benachrichtigung auslösen können, sind:

  • Übermäßige Wakelocks: 1 Teil-Wakelock wird eine Stunde lang gehalten, wenn der Bildschirm ausgeschaltet ist.
  • Übermäßige Hintergrunddienste: Wenn die App auf API-Level 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 Apps, die im Hintergrund ausgeführt werden und sich im Status „Eingeschränkt“ befinden, beispielsweise die folgenden Einschränkungen:

  • Dienste im Vordergrund können nicht gestartet werden.
  • Vorhandene Dienste im Vordergrund werden aus dem Vordergrund entfernt.
  • Alarme 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 Broadcast-Nachricht BOOT_COMPLETED oder die 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 Broadcast-Nachrichten zu Netzwerkaktivitäten

Apps, die auf Android 7.0 (API-Level 24) ausgerichtet sind, empfangen keine CONNECTIVITY_ACTION Broadcast-Nachrichten, wenn sie sich in ihrem Manifest für den Empfang dieser Nachrichten registrieren. Prozesse, die von dieser Broadcast-Nachricht abhängen, werden nicht gestartet. Dies kann ein Problem für Apps darstellen, die auf Netzwerkänderungen warten oder Netzwerkaktivitäten im Bulk ausführen möchten, wenn das Gerät mit einem Netzwerk mit Datentarif ohne Mengenbegrenzung verbunden ist. Im Android-Framework gibt es bereits mehrere Lösungen, um diese Einschränkung zu umgehen. Die Wahl der richtigen Lösung hängt jedoch davon ab, was Ihre App erreichen soll.

Hinweis: Ein BroadcastReceiver, der mit Context.registerReceiver() registriert wurde, empfängt diese Broadcast-Nachrichten weiterhin, während die App ausgeführt wird.

Netzwerkjobs für Verbindungen mit Datentarif ohne Mengenbegrenzung planen

Wenn Sie die JobInfo.Builder Klasse verwenden, um Ihr JobInfo Objekt zu erstellen, wenden Sie die setRequiredNetworkType() Methode 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 mit Datentarif ohne Mengenbegrenzung 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 onStartJob() Methode in der angegebenen JobService.class auszuführen. Weitere Beispiele für die Implementierung von JobScheduler finden Sie in der JobScheduler-Beispiel-App.

Eine neue Alternative zu JobScheduler ist WorkManager, eine API, mit der Sie Hintergrundaufgaben planen können, deren Abschluss garantiert werden muss, unabhängig davon, ob der App-Prozess vorhanden ist oder nicht. WorkManager wählt die geeignete Methode zum Ausführen der Aufgabe aus (entweder direkt in einem Thread in Ihrem App-Prozess sowie mit JobScheduler, FirebaseJobDispatcher oder AlarmManager) basierend auf Faktoren wie dem API-Level des Geräts. 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 überwachen, während die App ausgeführt wird

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 NetworkRequest.Builder Klasse. registerNetworkCallback() übergibt das NetworkRequest Objekt dann an das System. Wenn die Netzwerkbedingungen erfüllt sind, erhält die App einen Callback, um die onAvailable() Methode auszuführen, die in der ConnectivityManager.NetworkCallback Klasse definiert ist.

Die App erhält weiterhin Callbacks, bis sie beendet wird oder unregisterNetworkCallback() aufgerufen wird.

Einschränkungen beim Empfang von Broadcast-Nachrichten zu Bildern und Videos

In Android 7.0 (API-Level 24) können Apps keine ACTION_NEW_PICTURE- oder ACTION_NEW_VIDEO-Broadcast-Nachrichten 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 an Inhalts-URIs auslösen

Um Jobs bei Änderungen an Inhalts-URIs auszulösen, erweitert Android 7.0 (API-Level 24) die JobInfo API um die folgenden Methoden:

JobInfo.TriggerContentUri()
Kapselt Parameter, die erforderlich sind, um einen Job bei Änderungen an Inhalts-URIs auszulösen.
JobInfo.Builder.addTriggerContentUri()
Übergibt ein TriggerContentUri Objekt an JobInfo. Ein ContentObserver überwacht den gekapselten Inhalts-URI. Wenn mehrere TriggerContentUri Objekte mit einem Job verknüpft sind, stellt das System einen Callback bereit, auch wenn es nur eine Änderung an einem der Inhalts-URIs meldet.
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 notifyForDescendants Parameter, der an registerContentObserver() übergeben wird.

Hinweis: TriggerContentUri() kann nicht in Kombination mit setPeriodic() oder setPersisted() verwendet werden. Um kontinuierlich auf Inhaltsänderungen zu warten, planen Sie ein neues JobInfo bevor die JobService der App den letzten Callback verarbeitet hat.

Im folgenden Codebeispiel wird ein Job so geplant, dass er 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.

Bestimmen, welche Inhalts-Authorities einen Job ausgelöst haben

Android 7.0 (API-Level 24) erweitert auch JobParameters, damit Ihre App nützliche Informationen darüber erhält, welche Inhalts-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. wenn 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 von Inhalts-Authorities zurück, die den Job ausgelöst haben. Wenn das zurückgegebene Array nicht null ist, rufen Sie mit getTriggeredContentUris() die Details zu den geänderten URIs ab.

Im folgenden Codebeispiel wird die JobService.onStartJob() Methode überschrieben und die Inhalts-Authorities 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 die Ausführung auf Geräten mit wenig Arbeitsspeicher oder unter Bedingungen mit wenig Arbeitsspeicher optimieren, können Sie die Leistung und die Nutzerfreundlichkeit verbessern. Wenn Sie Abhängigkeiten von Hintergrunddiensten und im Manifest registrierten impliziten Broadcast-Empfängern entfernen, kann Ihre App auf solchen Geräten besser ausgeführt werden. Obwohl Android 7.0 (API-Level 24) Maßnahmen ergreift, um einige dieser Probleme zu verringern, empfehlen wir , Ihre App so zu optimieren, dass sie vollständig ohne diese Hintergrundprozesse ausgeführt werden kann.

Mit den folgenden Android Debug Bridge-Befehlen (ADB) können Sie das App-Verhalten testen, wenn Hintergrundprozesse deaktiviert sind:

  • Geben Sie den folgenden Befehl ein, um Bedingungen zu simulieren, unter denen implizite Broadcast-Nachrichten 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 Broadcast-Nachrichten 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 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