Prozesse und Threads – Übersicht

Wenn eine Anwendungskomponente gestartet wird und die Anwendung über keine anderen Komponenten verfügt startet das Android-System einen neuen Linux-Prozess für die Anwendung mit einem einzelnen Thread Ausführung. Standardmäßig werden alle Komponenten derselben Anwendung im selben Prozess und Thread ausgeführt. namens main.

Wenn eine Anwendungskomponente gestartet wird und bereits ein Prozess vorhanden ist da eine andere Komponente aus der Anwendung bereits gestartet wurde, beginnt innerhalb dieses Prozesses und verwendet denselben Ausführungsthread. Sie können jedoch Komponenten in Ihrer Anwendung in separaten Prozessen ausgeführt werden. Sie können auch zusätzliche Threads für jeden Prozess.

In diesem Dokument wird erläutert, wie Prozesse und Threads in einer Android-App funktionieren.

Prozesse

Standardmäßig werden alle Komponenten einer Anwendung im selben Prozess ausgeführt. Die meisten Anwendungen ändern Sie dies nicht. Sollten Sie jedoch feststellen, dass Sie steuern müssen, Komponente gehört, können Sie dies in der Manifest-Datei tun.

Der Manifesteintrag für jeden Typ von Komponentenelement – <activity>, <service>, <receiver> und <provider> – unterstützt ein android:process-Attribut, das einen in dem die Komponente läuft. Sie können dieses Attribut so festlegen, dass jede Komponente ausgeführt wird, dass einige Komponenten einen Prozess gemeinsam haben, während andere nicht.

Sie können auch android:process, damit Komponenten verschiedener Anwendungen im selben Dies geschieht nur, wenn die Anwendungen dieselbe Linux-Nutzer-ID haben und mit dem über dieselben Zertifikate.

Die <application> unterstützt auch ein android:process-Attribut, mit dem Sie ein Standardwert, der für alle Komponenten gilt.

Android kann irgendwann einen Prozess beenden, wenn die Ressourcen die für andere Prozesse benötigt werden, die eine unmittelbare Reaktion auf den Nutzer bieten. Anwendung Komponenten, die in einem heruntergefahrenen Prozess ausgeführt werden, werden entsprechend vernichtet. Ein Prozess wird gestartet für diese Komponenten, wenn es Arbeit für sie gibt.

Bei der Entscheidung, welche Prozesse heruntergefahren werden, wägt das Android-System deren relative Bedeutung für Nutzenden. Beispielsweise wird damit ein Prozess beendet, der Aktivitäten hostet, die nicht mehr im Vergleich zu einem Prozess, der sichtbare Aktivitäten hostet. Die Entscheidung, ob einen Prozess beenden, hängt daher vom Status der Komponenten ab, die in diesem Prozess ausgeführt werden.

Die Details des Prozesslebenszyklus und seine Beziehung zu den Anwendungsstatus werden in den Prozesse und App-Lebenszyklus:

Threads

Beim Starten einer Anwendung erstellt das System einen Ausführungsthread für die Anwendung. wird Hauptthread genannt. Dieser Thread ist sehr wichtig, da er für das Senden von Ereignissen die entsprechenden UI-Widgets, einschließlich Zeichenereignissen. Es ist auch fast immer der Thread, in dem die Anwendung mit Komponenten interagiert. des Android-UI-Toolkits aus android.widget und android.view Paket. Aus diesem Grund ist der Hauptthread den sogenannten UI-Thread. Unter besonderen Umständen kann jedoch der Haupt- möglicherweise nicht der UI-Thread ist. Weitere Informationen finden Sie unter Thread Anmerkungen.

Das System erstellt keinen separaten Thread für jede Instanz einer Komponente. Alle Komponenten, die im selben Prozess ausgeführt werden, werden im Benutzeroberflächen-Thread instanziiert und Systemaufrufe an werden alle Komponenten aus diesem Thread gesendet. Folglich werden Methoden, die auf System- Callbacks wie onKeyDown() um Nutzeraktionen oder eine Lebenszyklus-Callback-Methode zu melden, werden immer im UI-Thread des Prozesses ausgeführt.

Wenn der Nutzer beispielsweise eine Schaltfläche auf dem Bildschirm berührt, sendet der UI-Thread Ihrer App das Ereignis an das Widget, das wiederum den Status „Betätigt“ festlegt und eine Anforderung für ungültig erklärt, in die Ereigniswarteschlange ein. Der UI-Thread reiht die Anfrage aus der Warteschlange ein und benachrichtigt das Widget, die Anfrage neu zu zeichnen. selbst.

Wenn Sie Ihre Anwendung nicht ordnungsgemäß implementieren, kann dieses Single-Thread-Modell kann zu einer schlechten Leistung führen, wenn Ihre App als Reaktion auf Nutzerinteraktionen intensive Arbeit ausführt. Das Ausführen langer Vorgänge im UI-Thread, z. B. Netzwerkzugriff oder die gesamte Benutzeroberfläche blockiert. Wenn der Thread blockiert ist, können keine Ereignisse einschließlich Zeichenereignissen.

Aus der Perspektive der Nutzenden bleibt hängen. Noch schlimmer: Wenn der UI-Thread länger als ein paar Sekunden blockiert ist, wird dem Nutzer die Meldung "App, die nicht antworten“ (ANR). Der Nutzer kann die Anwendung dann schließen oder sogar deinstallieren. .

Beachten Sie, dass das Android-UI-Toolkit nicht threadsicher ist. Manipulieren Sie Ihre UI aus einem Worker-Thread. Nehmen Sie sämtliche Änderungen an Ihrer Benutzeroberfläche von der Benutzeroberfläche aus vor. Diskussions-Thread. Für das Single-Thread-Modell von Android gelten zwei Regeln:

  1. Blockiere nicht den UI-Thread.
  2. Greifen Sie nicht außerhalb des UI-Threads auf das Android-UI-Toolkit zu.

Worker-Threads

Aufgrund dieses Single-Thread-Modells ist es entscheidend, der Benutzeroberfläche der Anwendung blockieren, damit der Benutzeroberflächen-Thread nicht blockiert wird. Wenn Sie Vorgänge ausführen müssen, die nicht unverzüglich erfolgen, achten Sie darauf, sie in einem separaten Hintergrund oder Worker-Threads. Denken Sie daran, dass Sie die UI nur von einem anderen Thread aus aktualisieren können. die UI bzw. den Hauptthread.

Um Sie bei der Einhaltung dieser Regeln zu unterstützen, bietet Android mehrere Möglichkeiten, von anderen Apps aus auf den UI-Thread zuzugreifen. Threads. Hier ist eine Liste mit hilfreichen Methoden:

Im folgenden Beispiel wird View.post(Runnable) verwendet:

Kotlin

fun onClick(v: View) {
    Thread(Runnable {
        // A potentially time consuming task.
        val bitmap = processBitMap("image.png")
        imageView.post {
            imageView.setImageBitmap(bitmap)
        }
    }).start()
}

Java

public void onClick(View v) {
    new Thread(new Runnable() {
        public void run() {
            // A potentially time consuming task.
            final Bitmap bitmap =
                    processBitMap("image.png");
            imageView.post(new Runnable() {
                public void run() {
                    imageView.setImageBitmap(bitmap);
                }
            });
        }
    }).start();
}

Diese Implementierung ist Thread-sicher, da der Hintergrundvorgang von einem separaten Thread aus erfolgt. während ImageView immer über den UI-Thread bearbeitet wird.

Mit zunehmender Komplexität des Vorgangs kann diese Art von Code jedoch kompliziert werden schwierig zu verwalten ist. Für komplexere Interaktionen mit einem Worker-Thread könnten Sie mit einem Handler in Ihrem Worker-Thread um vom UI-Thread übermittelte Nachrichten zu verarbeiten. Eine ausführliche Erklärung dazu, wie Sie Aufgaben an Hintergrund-Threads planen und an den UI-Thread zurückkommunizieren, siehe Hintergrundarbeit – Übersicht

Threadsichere Methoden

In einigen Situationen werden die von Ihnen implementierten Methoden von mehr als einem Thread aus aufgerufen. daher so geschrieben werden, dass sie threadsicher sind.

Dies gilt vor allem für Methoden, die remote aufgerufen werden können, z. B. Methoden in einem gebundenen Dienst. Wenn ein Anruf auf einem die in einem IBinder implementiert ist, aus demselben Prozess stammt, in dem die IBinder ausgeführt wird, wird die Methode im Thread des Aufrufers ausgeführt. Wenn der Aufruf jedoch aus einem anderen Prozess stammt, wird die Methode in einem Thread ausgeführt, der aus Ein Thread-Pool, den das System im selben Prozess wie IBinder verwaltet. Sie wird nicht im UI-Thread des Prozesses ausgeführt.

Während die Funktion Die Methode onBind() wird über den UI-Thread des Prozess des Dienstes, Methoden, die im Objekt implementiert sind, das von onBind() zurückgegeben wird, wie Unterklasse, die Methoden für Remoteprozeduraufrufe (Remote Procedure Call, RPC) implementiert und aus Threads aufgerufen wird im Pool. Da ein Dienst mehr als einen Client haben kann, kann mehr als ein Pool-Thread interagieren zur selben IBinder-Methode, d. h., IBinder-Methoden müssen Thread-sicher implementiert.

Ebenso kann ein Contentanbieter Datenanfragen empfangen, die von anderen Prozessen stammen. ContentResolver und ContentProvider wie die Interprozesskommunikation (IPC) gemanagt wird, aber die ContentProvider-Methoden, die auf diese Anfragen antworten, query(), insert(), delete(), update(), und getType() – sind wird aus einem Thread-Pool im Prozess des Contentanbieters aufgerufen, nicht aus der Benutzeroberfläche. Thread für den Prozess. Da diese Methoden von beliebig vielen Threads an der müssen auch sie implementiert werden, damit sie threadsicher sind.

Interprozesskommunikation

Android bietet einen Mechanismus für IPC mit RPCs, bei denen eine Methode von einer Aktivität oder einer anderen Anwendung aufgerufen wird. -Komponente, die jedoch remote in einem anderen Prozess ausgeführt wird, wobei alle Ergebnisse an den Anrufer. Dabei werden ein Methodenaufruf und die zugehörigen Daten in eine Ebene zerlegt, die das Betriebssystem zu verstehen, sie vom lokalen Prozess und Adressraum zum Remote-Prozess zu übertragen und dann den Anruf dort neu zusammensetzen und ausführen.

Rückgabewerte werden dann in die entgegengesetzte Richtung übertragen werden. Android stellt den gesamten Code zur Durchführung dieser IPC bereit. Transaktionen, sodass Sie sich auf die Definition und Implementierung der RPC-Programmierschnittstelle konzentrieren können.

Damit IPC ausgeführt werden kann, muss Ihre Anwendung mithilfe von bindService() an einen Dienst gebunden werden. Weitere Informationen finden Sie in der Übersicht über die Dienste.