Systemeinschränkungen für Hintergrundarbeit

Hintergrundprozesse können speicher- und energieverbrauchsintensiv sein. Ein impliziter Broadcast kann beispielsweise viele Hintergrundprozesse starten, die zum Beobachten registriert wurden, auch wenn diese Prozesse möglicherweise nicht viel Arbeit ausführen. Dies kann sich erheblich auf die Geräteleistung und die Nutzererfahrung auswirken.

Achten Sie darauf, dass Sie die richtige API für Ihre Hintergrundaufgabe verwenden, um Systemeinschränkungen zu vermeiden. Die Dokumentation Hintergrundaufgaben – Übersicht hilft Ihnen dabei, die richtige API für Ihre Anforderungen auszuwählen.

Vom Nutzer initiierte Einschränkungen

Wenn eine App eines der unter Android Vitals beschriebenen schlechten Verhaltensweisen aufweist, wird der Nutzer vom System aufgefordert, den Zugriff der App auf Systemressourcen einzuschränken.

Wenn das System feststellt, dass eine App übermäßig viele Ressourcen verbraucht, wird der Nutzer benachrichtigt und hat die Möglichkeit, die Aktionen der App einzuschränken. Folgende Verhaltensweisen können die Meldung auslösen:

  1. Übermäßige Wakelocks: 1 Teil-Wakelock wird für eine Stunde gehalten, wenn der Bildschirm ausgeschaltet ist.
  2. Übermäßige Hintergrunddienste: Wenn die App auf API-Level unter 26 ausgerichtet ist und übermäßig viele Hintergrunddienste enthält.

Die genauen Einschränkungen werden vom Gerätehersteller festgelegt. Bei AOSP-Builds können eingeschränkte Apps beispielsweise keine Jobs ausführen, keine Alarme auslösen und das Netzwerk nicht nutzen, es sei denn, die App wird im Vordergrund ausgeführt.

Einschränkungen für den Empfang von Broadcasts zu Netzwerkaktivitäten

Apps empfangen keine CONNECTIVITY_ACTION-Broadcasts, wenn sie sich für den Empfang in ihrem Manifest registrieren. Außerdem werden Prozesse, die von diesem Broadcast abhängig sind, nicht gestartet. Dies könnte ein Problem für Apps darstellen, die auf Netzwerkänderungen warten oder Bulk-Netzwerkaktivitäten ausführen möchten, wenn das Gerät mit einem kostenlosen Netzwerk verbunden ist. Im Android-Framework gibt es bereits mehrere Lösungen, um diese Einschränkung zu umgehen. Die Auswahl der richtigen Lösung hängt jedoch davon ab, was Sie mit Ihrer App erreichen möchten.

Arbeiten für kostenlose Verbindungen planen

Fügen Sie beim Erstellen einer WorkRequest ein NetworkType.UNMETERED-Constraint hinzu.

fun scheduleWork(context: Context) {
    val workManager = WorkManager.getInstance(context)
    val workRequest = OneTimeWorkRequestBuilder<MyWorker>()
       .setConstraints(
           Constraints.Builder()
               .setRequiredNetworkType(NetworkType.UNMETERED)
               .build()
           )
       .build()

    workManager.enqueue(workRequest)
}

Wenn die Bedingungen für Ihre Arbeit erfüllt sind, erhält die App einen Callback, mit dem die Methode doWork() in der angegebenen Worker-Klasse ausgeführt wird.

Netzwerkkonnektivität überwachen, während die App ausgeführt wird

Ausgeführte Anwendungen können weiterhin mit einem registrierten BroadcastReceiver auf CONNECTIVITY_CHANGE warten. Die ConnectivityManager API bietet jedoch eine robustere Methode, einen Callback nur dann anzufordern, wenn die angegebenen Netzwerkbedingungen erfüllt sind.

NetworkRequest-Objekte definieren die Parameter des Netzwerk-Callbacks in Form von NetworkCapabilities. Sie erstellen NetworkRequest-Objekte mit der Klasse NetworkRequest.Builder. registerNetworkCallback übergibt dann das NetworkRequest-Objekt an das System. Wenn die Netzwerkbedingungen erfüllt sind, empfängt die App einen Callback, mit dem die onAvailable()-Methode ausgeführt wird, die in ihrer ConnectivityManager.NetworkCallback-Klasse definiert ist.

Die Anwendung empfängt Rückrufe, bis sie entweder beendet oder unregisterNetworkCallback() aufruft.

Einschränkungen für den Empfang von Bild- und Videoübertragungen

Apps können keine ACTION_NEW_PICTURE- oder ACTION_NEW_VIDEO-Broadcasts senden oder empfangen. Durch diese Einschränkung werden die Auswirkungen auf Leistung und Nutzererfahrung verringert, wenn mehrere Anwendungen aktiviert werden müssen, um ein neues Bild oder Video zu verarbeiten.

Herausfinden, welche Content-Behörden Aufgaben ausgelöst haben

Mit WorkerParameters erhält Ihre App nützliche Informationen darüber, welche Content-Zertifizierungsstellen und URIs die Ausführung ausgelöst haben:

List<Uri> getTriggeredContentUris()

Gibt eine Liste der URIs zurück, die die Arbeit ausgelöst haben. Dieser Wert ist leer, wenn entweder keine URIs die Arbeit ausgelöst haben (z. B. aufgrund einer Frist oder aus einem anderen Grund) oder die Anzahl der geänderten URIs größer als 50 ist.

List<String> getTriggeredContentAuthorities()

Gibt eine Stringliste mit Contentautoritäten zurück, die die Arbeit ausgelöst haben. Wenn die zurückgegebene Liste nicht leer ist, verwenden Sie getTriggeredContentUris(), um die Details zu den URIs abzurufen, die geändert wurden.

Der folgende Beispielcode überschreibt die Methode CoroutineWorker.doWork() und zeichnet die Inhaltsstellen und URIs auf, die den Job ausgelöst haben:

class MyWorker(
    appContext: Context,
    params: WorkerParameters
): CoroutineWorker(appContext, params)
    override suspend fun doWork(): Result {
        StringBuilder().apply {
            append("Media content has changed:\n")
            params.triggeredContentAuthorities
                .takeIf { it.isNotEmpty() }
                ?.let { authorities ->
                    append("Authorities: ${authorities.joinToString(", ")}\n")
                    append(params.triggeredContentUris.joinToString("\n"))
                } ?: append("(No content)")
            Log.i(TAG, toString())
        }
        return Result.success()
    }
}

App mit Systemeinschränkungen testen

Wenn Sie Ihre Anwendungen für die Ausführung auf Geräten mit wenig Arbeitsspeicher oder mit geringem Arbeitsspeicher optimieren, können Sie die Leistung und die Nutzerfreundlichkeit verbessern. Das Entfernen von Abhängigkeiten von Hintergrunddiensten und Manifest-registrierten impliziten Broadcast-Empfängern kann dazu beitragen, dass Ihre App auf solchen Geräten besser läuft. Es wird empfohlen, dass Sie Ihre App so optimieren, dass sie ohne diese Hintergrundprozesse vollständig ausgeführt wird.

Mit einigen zusätzlichen 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, in 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

App weiter optimieren

Weitere Möglichkeiten zur Optimierung des Verhaltens Ihrer Hintergrundaufgaben finden Sie unter Akkunutzung für APIs zur Aufgabenplanung optimieren.