Prozesse und App-Lebenszyklus

In den meisten Fällen wird jede Android-Anwendung in einem eigenen Linux-Prozess ausgeführt. Dieser Prozess wird für die Anwendung erstellt, wenn ein Teil ihres Codes ausgeführt werden muss. Er bleibt so lange aktiv, bis das System den Arbeitsspeicher für andere Anwendungen benötigt und er nicht mehr benötigt wird.

Eine ungewöhnliche und grundlegende Funktion von Android ist, dass die Lebensdauer eines Anwendungsprozesses nicht direkt von der Anwendung selbst gesteuert wird. Stattdessen wird sie vom System anhand einer Kombination aus den Teilen der Anwendung bestimmt, die dem System bekannt sind, wie wichtig diese für den Nutzer sind und wie viel Arbeitsspeicher insgesamt im System verfügbar ist.

Es ist wichtig, dass Anwendungsentwickler verstehen, wie sich verschiedene Anwendungskomponenten (insbesondere Activity, Service und BroadcastReceiver) auf die Lebensdauer des Anwendungsprozesses auswirken. Wenn diese Komponenten nicht richtig verwendet werden, kann das System den Prozess der Anwendung beenden, während wichtige Aufgaben ausgeführt werden.

Ein häufiges Beispiel für einen Fehler im Prozesslebenszyklus ist ein BroadcastReceiver, der einen Thread startet, wenn er in seiner BroadcastReceiver.onReceive()-Methode eine Intent empfängt und dann von der Funktion zurückkehrt. Wenn die Verbindung wiederhergestellt ist, betrachtet das System die BroadcastReceiver als inaktiv und ihren Hostingprozess als nicht mehr erforderlich, es sei denn, andere Anwendungskomponenten sind darin aktiv.

So kann das System den Prozess jederzeit beenden, um Arbeitsspeicher zurückzugewinnen, und beendet dabei auch den im Prozess laufenden Thread. Die Lösung für dieses Problem besteht in der Regel darin, einen JobService über den BroadcastReceiver zu planen, damit das System weiß, dass im Prozess aktive Arbeit stattfindet.

Um zu bestimmen, welche Prozesse bei wenig Arbeitsspeicher beendet werden sollen, ordnet Android jeden Prozess einer Wichtigkeitshierarchie zu, die auf den darin ausgeführten Komponenten und deren Status basiert. Diese Prozesstypen sind nach ihrer Wichtigkeit geordnet:

  1. Ein Prozess im Vordergrund ist für die aktuelle Aktion des Nutzers erforderlich. Verschiedene Anwendungskomponenten können dazu führen, dass der enthaltene Prozess auf unterschiedliche Weise als Vordergrundprozess betrachtet wird. Ein Prozess wird als im Vordergrund ausgeführt betrachtet, wenn eine der folgenden Bedingungen erfüllt ist:
  2. Es gibt nur wenige solcher Prozesse im System und diese werden nur als letztes Mittel beendet, wenn der Arbeitsspeicher so niedrig ist, dass nicht einmal diese Prozesse weiter ausgeführt werden können. In der Regel ist das Gerät in einem Speicherauslagerungsstatus, sodass diese Aktion erforderlich ist, um die Nutzeroberfläche reaktionsschnell zu halten.

  3. Ein sichtbarer Prozess führt eine Aufgabe aus, die dem Nutzer derzeit bewusst ist. Wenn er beendet wird, hat das eine spürbare negative Auswirkung auf die Nutzererfahrung. Ein Prozess gilt unter den folgenden Bedingungen als sichtbar:
    • Es wird eine Activity ausgeführt, die für den Nutzer auf dem Bildschirm sichtbar, aber nicht im Vordergrund ist (die onPause()-Methode wurde aufgerufen). Das kann beispielsweise passieren, wenn das Activity im Vordergrund als Dialogfeld angezeigt wird, hinter dem das vorherige Activity zu sehen ist.
    • Es hat eine Service, die als Dienst im Vordergrund ausgeführt wird, über Service.startForeground() (wodurch das System den Dienst als etwas behandelt, das dem Nutzer bekannt ist, oder im Wesentlichen so, als wäre er sichtbar).
    • Er hostet einen Dienst, den das System für eine bestimmte Funktion verwendet, die dem Nutzer bekannt ist, z. B. einen Live-Hintergrund oder einen Dienst für die Eingabemethode.

    Die Anzahl dieser Prozesse, die im System ausgeführt werden, ist weniger begrenzt als bei Prozessen im Vordergrund, aber dennoch relativ kontrolliert. Diese Prozesse gelten als äußerst wichtig und werden nur beendet, wenn dies erforderlich ist, um alle Prozesse im Vordergrund auszuführen.

  4. Ein Dienstprozess enthält eine Service, die mit der Methode startService() gestartet wurde. Auch wenn diese Prozesse für den Nutzer nicht direkt sichtbar sind, werden damit in der Regel Dinge ausgeführt, die für ihn wichtig sind (z. B. der Upload oder Download von Netzwerkdaten im Hintergrund). Daher werden solche Prozesse vom System immer ausgeführt, es sei denn, nicht genügend Arbeitsspeicher ist verfügbar, um alle Prozesse im Vordergrund und alle sichtbaren Prozesse zu behalten.

    Dienste, die schon lange laufen (z. B. 30 Minuten oder länger), werden möglicherweise herabgestuft, damit ihr Prozess in die Liste im Cache verschoben wird.

    Prozesse, die über einen längeren Zeitraum ausgeführt werden müssen, können mit setForeground erstellt werden. Bei einem regelmäßigen Prozess, der zu einer bestimmten Zeit ausgeführt werden muss, kann er über die AlarmManager geplant werden. Weitere Informationen finden Sie unter Unterstützung für lang andauernde Worker. So lassen sich Situationen vermeiden, in denen lang laufende Dienste, die übermäßig viele Ressourcen verbrauchen, z. B. durch Speicherlecks, verhindern, dass das System eine gute Nutzererfahrung bietet.

  5. Ein im Cache gespeicherter Prozess wird derzeit nicht benötigt. Das System kann ihn daher bei Bedarf beenden, wenn Ressourcen wie Arbeitsspeicher an anderer Stelle benötigt werden. In einem System, das sich normal verhält, sind dies die einzigen Prozesse, die an der Ressourcenverwaltung beteiligt sind.

    Ein gut funktionierendes System hat immer mehrere im Cache gespeicherte Prozesse verfügbar, um effizient zwischen Anwendungen zu wechseln. Außerdem werden die im Cache gespeicherten Apps bei Bedarf regelmäßig beendet. Nur in sehr kritischen Situationen kommt es dazu, dass alle im Cache befindlichen Prozesse beendet werden und Dienstprozesse beendet werden müssen.

    Da zwischengespeicherte Prozesse jederzeit vom System beendet werden können, sollten Apps alle Arbeiten beenden, während sie sich im Cache-Status befinden. Wenn von der App nutzerkritische Aufgaben ausgeführt werden müssen, sollte eine der oben genannten APIs verwendet werden, um die Aufgaben aus einem aktiven Prozessstatus auszuführen.

    Im Cache gespeicherte Prozesse enthalten häufig eine oder mehrere Activity-Instanzen, die für den Nutzer derzeit nicht sichtbar sind (ihre onStop()-Methode wurde aufgerufen und zurückgegeben). Wenn der Activity-Lebenszyklus richtig implementiert ist, hat das Beenden solcher Prozesse durch das System keine Auswirkungen auf die Nutzererfahrung, wenn sie zu dieser App zurückkehren. Der zuvor gespeicherte Status kann wiederhergestellt werden, wenn die zugehörige Aktivität in einem neuen Prozess neu erstellt wird. Beachten Sie, dass onDestroy() nicht garantiert aufgerufen wird, wenn ein Prozess vom System beendet wird. Weitere Informationen finden Sie unter Activity.

    Ab Android 13 erhält ein App-Prozess möglicherweise nur eine begrenzte oder gar keine Ausführungszeit, bis er in einen der oben genannten aktiven Lebenszyklusstatus wechselt.

    Im Cache gespeicherte Prozesse werden in einer Liste aufbewahrt. Die genaue Sortierrichtlinie für diese Liste ist eine Implementierungsangelegenheit der Plattform. Im Allgemeinen werden nützlichere Prozesse, z. B. solche, die die Startanwendung des Nutzers oder die letzte Aktivität des Nutzers hosten, vor anderen Arten von Prozessen beibehalten. Es können auch andere Richtlinien zum Beenden von Prozessen angewendet werden, z. B. feste Limits für die Anzahl der zulässigen Prozesse oder eine Begrenzung der Zeit, in der ein Prozess kontinuierlich im Cache bleiben kann.

Bei der Entscheidung, wie ein Prozess klassifiziert werden soll, orientiert sich das System an der wichtigsten Ebene aller derzeit im Prozess aktiven Komponenten. Weitere Informationen dazu, wie jede dieser Komponenten zum gesamten Lebenszyklus eines Prozesses und der Anwendung beiträgt, finden Sie in der Dokumentation zu Activity, Service und BroadcastReceiver.

Die Priorität eines Prozesses kann auch aufgrund anderer Abhängigkeiten erhöht werden, die ein Prozess hat. Wenn Prozess A beispielsweise mit dem Flag Context.BIND_AUTO_CREATE an eine Service gebunden ist oder in Prozess B eine ContentProvider verwendet, ist die Klassifizierung von Prozess B immer mindestens so wichtig wie die von Prozess A.