Systemeinschränkungen für Hintergrundaufgaben

Hintergrundprozesse können viel Arbeitsspeicher und Akkuleistung verbrauchen. Beispielsweise kann ein implizierter Broadcast viele Hintergrundprozesse starten, die sich für den Empfang registriert haben, auch wenn diese Prozesse nicht viel Arbeit erledigen. Dies kann erhebliche Auswirkungen auf die Geräteleistung und die Nutzerfreundlichkeit haben.

Verwenden Sie die richtige API für Ihre Hintergrundaufgabe, um Systembeschränkungen zu vermeiden. In der Dokumentation Hintergrundaufgaben – Übersicht finden Sie Informationen zur Auswahl der richtigen API für Ihre Anforderungen.

Vom Nutzer initiierte Einschränkungen

Wenn eine App einige der unter Android Vitals beschriebenen unerwünschten Verhaltensweisen zeigt, wird der Nutzer vom System aufgefordert, 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. Zu den Verhaltensweisen, die den Hinweis auslösen können, gehören:

  1. Übermäßige Wakelocks: 1 Teil-Wakelock, der eine Stunde lang gehalten wird, wenn das Display ausgeschaltet ist
  2. Übermäßige Hintergrunddienste: Wenn die App auf API-Level unter 26 ausgerichtet ist und übermäßige Hintergrunddienste hat

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

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

Apps erhalten 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. 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 eine Verbindung zu einem Netzwerk ohne Datenlimit herstellt. Im Android-Framework gibt es 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.

Arbeit für Verbindungen ohne Datenlimit planen

Fügen Sie beim Erstellen eines 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 Ihre App einen Callback, um die Methode doWork() in der angegebenen Worker-Klasse auszuführen.

Netzwerkverbindung überwachen, während die App ausgeführt wird

Ausgeführte Apps können weiterhin mit einem 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. Sie erstellen NetworkRequest-Objekte mit der Klasse NetworkRequest.Builder. registerNetworkCallback übergibt dann das NetworkRequest-Objekt an das System. Wenn die Netzwerkbedingungen erfüllt sind, erhält die App einen Callback, um die in ihrer ConnectivityManager.NetworkCallback-Klasse definierte Methode onAvailable() auszuführen.

Die App empfängt weiterhin Callbacks, bis sie entweder beendet wird oder unregisterNetworkCallback() aufruft.

Einschränkungen beim Empfang von Bild- und Videonachrichten

Apps können 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.

Ermitteln, welche Inhaltsbehörden die Arbeit ausgelöst haben

WorkerParameters ermöglicht es Ihrer App, nützliche Informationen darüber zu erhalten, welche Content-Authorities und URIs die Arbeit ausgelöst haben:

List<Uri> getTriggeredContentUris()

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

List<String> getTriggeredContentAuthorities()

Gibt eine Stringliste der Inhaltsautoritäten zurück, die die Arbeit ausgelöst haben. Wenn die zurückgegebene Liste nicht leer ist, verwenden Sie getTriggeredContentUris(), um die Details der geänderten URIs abzurufen.

Im folgenden Beispielcode wird die Methode CoroutineWorker.doWork() überschrieben und die Content Authorities und URIs aufgezeichnet, die den Job ausgelöst haben:

class MyWorker(
    appContext: Context,
    private val 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 unter Systemeinschränkungen testen

Wenn du deine Apps für die Ausführung auf Geräten mit wenig Arbeitsspeicher oder bei geringem Arbeitsspeicher optimierst, kannst du die Leistung und die 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. Es wird empfohlen, die App so zu optimieren, dass sie ohne diese Hintergrundprozesse ausgeführt werden kann.

Mit einigen zusätzlichen Android Debug Bridge-Befehlen (ADB) können Sie das Verhalten der App testen, wenn diese Hintergrundprozesse deaktiviert sind:

  • 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

App weiter optimieren

Weitere gute Möglichkeiten, das Verhalten von Hintergrundaufgaben zu optimieren, finden Sie in der Dokumentation Akkunutzung für APIs zur Aufgabenplanung optimieren.