Hintergrundoptimierung

Hintergrundprozesse können speicher- und energieintensiv sein. Beispiel: Der implizite Broadcast kann viele Hintergrundprozesse starten, darauf zu warten, auch wenn diese Prozesse vielleicht nicht viel Arbeit leisten. Dies kann mehrere erhebliche Auswirkungen auf die Geräteleistung und die Nutzererfahrung haben.

Um dieses Problem zu beheben, wird in Android 7.0 (API-Level 24) Folgendes angewendet: Einschränkungen:

  • Apps, die auf Android 7.0 (API-Level 24) und höher ausgerichtet sind, erhalten keine CONNECTIVITY_ACTION sendet eine Nachricht, wenn sie den Empfänger im Manifest deklarieren. Apps werden weiterhin CONNECTIVITY_ACTION Broadcasts empfangen, wenn sie sich registrieren BroadcastReceiver mit Context.registerReceiver() und dieser Kontext ist immer noch gültig.
  • Apps können keine ACTION_NEW_PICTURE- oder ACTION_NEW_VIDEO-Broadcasts senden oder empfangen. Diese Optimierung wirkt sich auf alle Apps aus, nicht nur auf Apps, 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 impliziten Broadcasts erforderlich sind. Beispiel: JobScheduler und Der neue WorkManager bietet zuverlässige Mechanismen zur Planung von unter bestimmten Bedingungen, wie z. B. eine Verbindung zu einem nicht getakteten erfüllt sind. Sie können jetzt auch JobScheduler verwenden um auf Veränderungen von 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 diesen Job im JobService Ihrer Anwendung 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 im System auswählen, kann der Nutzer wählen Sie eine der folgenden Optionen aus:

  • 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 optimiert, Hintergrundaufgaben auszuführen. je nachdem, wie die Nutzenden mit der App interagieren.
  • 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 übermäßig viele Ressourcen beansprucht, und die Möglichkeit, die Aktionen der App 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-Level unter 26 ausgerichtet ist und übermäßig viele Hintergrunddienste

Die genauen Einschränkungen werden vom Gerätehersteller festgelegt. Für Bei AOSP-Builds mit Android 9 (API-Level 28) oder höher werden Apps die im Hintergrund ausgeführt werden, haben 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 im "eingeschränkt" sendet das System die BOOT_COMPLETED-Übertragung oder LOCKED_BOOT_COMPLETED, bis die App für eine andere Person gestartet wird Gründe.

Die spezifischen Einschränkungen sind unter <ph type="x-smartling-placeholder"></ph> Einschränkungen bei der Energieverwaltung:

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 um sie in ihrem Manifest zu erhalten, und Prozesse, die von dieser wird 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: Eine BroadcastReceiver registriert mit Context.registerReceiver() empfängt diese Broadcasts 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:

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, 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. Mit dieser API können Sie Hintergrundaufgaben erstellen, garantiert eine Fertigstellung, unabhängig davon, ob der App-Prozess in Frage kommt 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

Aktive Apps können immer noch auf CONNECTIVITY_CHANGE mit einem registriert: BroadcastReceiver. 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() und übergibt dann das NetworkRequest-Objekt an das System. Wann? Wenn die Netzwerkbedingungen erfüllt sind, empfängt die App einen Callback, um die Methode onAvailable(), die in ihrer Klasse ConnectivityManager.NetworkCallback definiert ist.

Die App erhält weiterhin Rückrufe, bis sie entweder beendet oder aufgerufen wird. unregisterNetworkCallback()

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 Leistung und Nutzererfahrung, wenn mehrere Apps um ein neues Bild oder Video zu verarbeiten. Android 7.0 (API-Level 24) erweitert JobInfo und JobParameters, um eine alternative Lösung bereitzustellen.

Jobs bei Änderungen des 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()
Kapselt Parameter, die zum Auslösen eines Jobs bei Änderungen des Inhalts-URI erforderlich sind.
JobInfo.Builder.addTriggerContentUri()
Übergibt ein TriggerContentUri-Objekt an JobInfo. Ein ContentObserver überwacht den gekapselten Inhalts-URI. Wenn einem Job mehrere TriggerContentUri-Objekte zugeordnet sind, stellt das System ein selbst wenn eine Änderung nur 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 dem notifyForDescendants-Parameter, der an registerContentObserver() übergeben wurde.

Hinweis: TriggerContentUri() kann nicht verwendet werden in Kombination mit setPeriodic() oder setPersisted(). Zur fortlaufenden Überwachung von Inhaltsänderungen planen Sie ein neues 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:

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, wird Ihre App empfängt einen Callback und ein JobParameters-Objekt wird an onStartJob() übergeben in MediaContentJob.class.

Ermitteln, welche Inhaltsbehörden einen Job ausgelöst haben

Mit Android 7.0 (API-Level 24) wird JobParameters auch auf erlaube deiner App, nützliche Informationen darüber zu erhalten, welche Inhaltsbehörden und URIs haben den Job ausgelöst:

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 (z. B. er 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 Sie getTriggeredContentUris() 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:

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

Apps für die Ausführung auf Geräten mit wenig Arbeitsspeicher oder mit wenig Arbeitsspeicher optimieren Bedingungen zu verbessern, um die Leistung und die Nutzererfahrung zu 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. Obwohl Unter Android 7.0 (API-Level 24) werden einige dieser Probleme reduziert. empfehlen Ihnen, Ihre App so zu optimieren, dass sie ohne diese und Hintergrundprozesse.

Die folgende Android Debug Bridge (ADB) Befehle können Ihnen dabei helfen, das App-Verhalten bei deaktivierten Hintergrundprozessen zu testen:

  • Um Bedingungen zu simulieren, bei 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
    
  • Um implizite Broadcasts und Hintergrunddienste wieder zu aktivieren, geben Sie den folgenden Befehl:
  • $ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND allow
    
  • Du kannst simulieren, dass der Nutzer deine App Bundesland für Akkunutzung im Hintergrund. Diese Einstellung verhindert, dass deine App ausgeführt werden kann im Hintergrund. Führen Sie dazu den folgenden Befehl in einem Terminalfenster aus:
  • $ adb shell cmd appops set <PACKAGE_NAME> RUN_ANY_IN_BACKGROUND deny