Android: Wann sollte ich einen Handler () verwenden und wann sollte ich einen Thread verwenden?

129

Wenn ich etwas zum asynchronen Ausführen benötige , z. B. eine lange laufende Aufgabe oder eine Logik, die das Netzwerk verwendet, oder aus irgendeinem Grund, funktioniert das Starten und Ausführen eines neuen Threads einwandfrei. Das Erstellen und Ausführen eines Handlers funktioniert ebenfalls. Was ist der Unterschied? Wann sollte ich jeden verwenden? Was sind die Vorteile / Gründe für die Verwendung von a Handlerund nicht von a Thread?

PS. - Lassen Sie uns diese Frage ignorieren AsyncTask. - Der Handler().postDelayedAnwendungsfall ist mir klar. Um dieser Frage willen nehmen wir an, dass ich die Aufgabe sofort starten muss.

JRun
quelle
In Ihrer Situation gehen Sie einfach geradeaus und verwenden Sie einen neuen Thread. Mein nächster Vorschlag wäre AsyncTask, aber das ist nicht das, was Sie eindeutig wollen. Handler werden meistens verwendet, wenn Sie einer ausführbaren Datei eine Verzögerung oder eine andere Art der Anpassung hinzufügen möchten.
Kabuto178
1
@ kabuto178 Nun, es gibt andere Vorteile der Handler, die es wert sind, erwähnt zu werden, dass Sie übersprungen haben. Zum Beispiel in der Lage zu sein, mit dem UI-Thread von einem separaten Thread aus zu interagieren ..
Tony9099

Antworten:

168

Wenn alles, was Sie tun, "schwer" ist, sollten Sie es in einem Thread tun. Wenn Sie es nicht explizit in einem eigenen Thread starten, wird es auf dem Hauptthread (UI) ausgeführt, der von Ihren Benutzern als nervös oder langsam reagierend empfunden werden kann.

Interessanterweise ist es bei Verwendung eines Threads häufig nützlich, einen Handler auch als Kommunikationsmittel zwischen dem von Ihnen gestarteten Arbeitsthread und dem Hauptthread zu verwenden.

Eine typische Thread / Handler-Interaktion könnte ungefähr so ​​aussehen:

Handler h = new Handler(){
    @Override
    public void handleMessage(Message msg){
        if(msg.what == 0){
            updateUI();
        }else{
            showErrorDialog();
        }
    }
};

Thread t = new Thread() {
    @Override
    public void run(){
        doSomeWork();
        if(succeed){
            //we can't update the UI from here so we'll signal our handler and it will do it for us.
            h.sendEmptyMessage(0);
        }else{
            h.sendEmptyMessage(1);
        }
    }   
};

Im Allgemeinen sollten Sie jedoch jedes Mal einen Thread verwenden, wenn Sie Arbeiten ausführen, die lange dauern oder sehr intensiv sein können (z. B. Netzwerk, Datei-E / A, schwere Arithmetik usw.).

FoamyGuy
quelle
Vielen Dank für die schnelle Antwort und den Zeitaufwand (und die Geschwindigkeit Ihrer Antwort !!)! Lassen Sie mich sehen, ob ich Folgendes habe: Der Handler wurde entwickelt, um die nicht blockierende Kommunikation zwischen Arbeitsthreads und dem UI-Thread zu erleichtern.
JRun
3
@JRun Das ist eine der Verwendungen ja. In der Beschreibung des Handlers in den Java-Dokumenten finden Sie einige nützliche Informationen. Einschließlich einer anderen Verwendung (zum Planen von Nachrichten und ausführbaren Dateien, die zu einem späteren Zeitpunkt ausgeführt werden sollen).
FoamyGuy
schön erklärt @FoamyGuy!
Tony9099
Hallo, ist es garantiert, dass danach ausgeführt updateUI()wird onCreateView(nachdem neue Ansichten geladen wurden)?
Zyoo
1
Warum ist es message.what()? Wäre es nicht einfach so if(msg == 0){? Vielen Dank! :)
Ruchir Baronia
64

Handler und Thread sind wirklich zwei verschiedene Dinge.

Es muss ein Thread erstellt werden, um Jobs mit langer Laufzeit auszuführen.

Ein Handler ist ein sehr praktisches Objekt für die Kommunikation zwischen zwei Threads (zum Beispiel: Ein Hintergrundthread muss die Benutzeroberfläche aktualisieren. Sie können einen Handler verwenden, um Runnable von Ihrem Hintergrundthread an den UI-Thread zu senden).

Sie haben also nicht die Wahl zwischen Handler oder Thread. Verwenden Sie einen Faden, um schwere Arbeiten zu erledigen! (Sie können einen Handler verwenden, wenn Ihr Hintergrund-Thread einen Job auslöst, der in einem anderen Thread ausgeführt werden soll - meistens im UI-Thread.)

ben75
quelle
Vielen Dank für die schnelle Antwort und den Zeitaufwand (und die Geschwindigkeit Ihrer Antwort !!)!
JRun
28

Handlerund Threadsind zwei verschiedene Dinge, aber sie widersprechen sich nicht. Sie können a Handlerund a Threadgleichzeitig haben und tatsächlich Handlermuss jeder in a laufen Thread.

Weitere Informationen finden Sie in diesem Artikel .

Geben Sie hier die Bildbeschreibung ein

pierrotlefou
quelle
19

A Handlerläuft auf demselben Thread, a Threadläuft auf einem anderen Thread.

Verwenden Sie einen Handler, wenn Sie etwas auf demselben Thread ausführen müssen , normalerweise ein GUI-Element oder ähnliches.

Verwenden Sie einen Thread, wenn Sie den Haupt-Thread frei halten möchten, um andere Dinge zu tun . Verwenden Sie dies für alles, was viel Zeit in Anspruch nimmt.

PearsonArtPhoto
quelle
6
Warum sollte ich einen Handler verwenden, wenn ich etwas auf demselben Thread ausführen möchte? Was ist der Zweck der Methode mHandler.post (...)?
Elias
1
Elias, in einem solchen Fall können Sie den Handler verwenden, wenn eine bestimmte Aufgabe nach einer bestimmten Zeit ausgeführt werden soll oder wenn eine Aufgabe alle X Zeiten wiederholt werden soll. Wenn Sie diese Dinge nicht verwenden möchten, haben Sie Recht. Es ist nicht wert, einen Handler zu verwenden. Sie können die GUI-Dinge einfach genau dort ausführen und dann, weil Sie sich sowieso im UI-Thread befinden, da der Handler auf dem Thread ausgeführt wird, in dem er erstellt wurde.
Tony9099
14

Handler sind die beste Art der Kommunikation zwischen dem Hintergrund und dem UI-Thread. Im Allgemeinen sind Handler der Nachrichtenwarteschlange eines Threads zugeordnet und werden zum Senden von Nachrichten verwendet und können an die Nachricht ausgeführt werden.

VERWENDEN:

Thread: Zum Ausführen von Aufgaben im Saperate- Thread (Hintergrund-Thread) als im UI-Thread. (Hilft, den UI-Thread zu entsperren)

Handler Wird verwendet, um zwischen der Benutzeroberfläche und dem Hintergrund-Thread zu kommunizieren.

Schauen Sie sich diesen Artikel an

Saubhagya Ranjan Das
quelle
4

Wenn Sie die Benutzeroberfläche von einem neuen Thread aktualisieren müssen, müssen Sie mit dem Benutzeroberflächenthread synchronisieren.

Sie können hierfür die android.os.Handler-Klasse oder die AsyncTasks-Klasse verwenden.

Die Handler-Klasse kann die Benutzeroberfläche aktualisieren. Ein Handler bietet Methoden zum Empfangen von Instanzen der Message- oder Runnable-Klasse.

Sie können Nachrichten über die sendMessage-Methode (Message msg) oder über die sendEmptyMessage () -Methode posten.

... mehr Infos hier über Threads etc. (enthält Turorials für die verschiedenen Threading- und Synchronisationsmechanismen und wann was zu verwenden ist)

Beachwalker
quelle
Vielen Dank, dass Sie sich die Zeit genommen haben, meine Frage zu beantworten. Ich liebe Lars Vogels Blog, er ist sehr aufschlussreich und leicht zu verfolgen. Vielen Dank!
JRun
2

Was sind die Vorteile / Gründe für die Verwendung eines Handlers und nicht eines Threads?

Mit einem Handler können Sie Nachrichten und RunnableObjekte senden und verarbeiten, die einem Thread zugeordnet sind MessageQueue. Jede HandlerInstanz ist einem einzelnen Thread und der Nachrichtenwarteschlange dieses Threads zugeordnet.

Wenn Sie ein neues erstellen Handler, wird es an die Thread- / Nachrichtenwarteschlange des Threads gebunden, der es erstellt. Ab diesem Zeitpunkt werden Nachrichten und ausführbare Dateien an diese Nachrichtenwarteschlange gesendet und ausgeführt, sobald sie aus der Nachrichtenwarteschlange kommen .

Es gibt zwei Hauptverwendungen für einen Handler:

  1. Planen von Nachrichten und ausführbaren Dateien , die zu einem späteren Zeitpunkt ausgeführt werden sollen
  2. So stellen Sie eine Aktion in die Warteschlange , die für einen anderen Thread als Ihren eigenen ausgeführt werden soll.

Wenn Sie Java-Threads verwenden, müssen Sie einige Dinge selbst erledigen - Synchronisieren mit dem Haupt-Thread, Abbrechen eines Threads usw.

Dieser einzelne Thread erstellt keinen Thread-Pool, es sei denn, Sie verwenden ThreadPoolExecutoroder ExecutorServiceAPI.

(Diese Frage wurde Ihren Kommentaren zur Blackbelt-Antwort entnommen.)

Warum nicht einen Executor verwenden? und selbst wenn ich dafür einen Handler verwenden wollte, wie?

Referenz: Artikel zur Thread-Leistung

Es gibt bestimmte Arten von Arbeiten, die auf hochparallele, verteilte Aufgaben reduziert werden können. Mit der schieren Menge der Arbeitspakete dies schafft, AsyncTaskund HandlerThreadnicht geeignet sind Klassen. Die Single-Threaded-Natur von AsyncTaskwürde die gesamte Threadpool-Arbeit in ein lineares System verwandeln. Die Verwendung der HandlerThreadKlasse würde andererseits erfordern, dass der Programmierer den Lastausgleich zwischen einer Gruppe von Threads manuell verwaltet.

ThreadPoolExecutor ist eine Hilfsklasse , um diesen Prozess zu vereinfachen. Diese Klasse verwaltet die Erstellung einer Gruppe von Threads, legt deren Prioritäten fest und verwaltet, wie die Arbeit auf diese Threads verteilt wird. Wenn die Arbeitslast zunimmt oder abnimmt, dreht sich die Klasse oder zerstört mehr Threads, um sich an die Arbeitslast anzupassen.

 BlockingQueue workQueue= new LinkedBlockingQueue<Runnable>(100); // Work pool size
 ThreadPoolExecutor executor = new ThreadPoolExecutor(
            Runtime.getRuntime().availableProcessors(),       // Initial pool size
            Runtime.getRuntime().availableProcessors(),       // Max pool size
            1, // KEEP_ALIVE_TIME
            TimeUnit.SECONDS, //  KEEP_ALIVE_TIME_UNIT
            workQueue);

Weitere Informationen finden Sie in diesem Entwicklerhandbuch zu create-threadpool .

In diesem Beitrag Handlererfahren Sie, wie Sie mehrere ausführbare Instanzen ausführen können. In diesem Fall werden alle RunnableAufgaben in einem einzigen Thread ausgeführt.

Android: Toast in einem Thread

Ravindra Babu
quelle
1

Handlerkann in Verbindung mit verwendet Threadwerden, um einen Warteschlangenmechanismus zu erstellen. Sie können das verwenden handler, um etwas auf dem zu postenThread Looper

Schwarzer Gürtel
quelle
Vielen Dank, dass Sie sich die Zeit genommen haben, meine Frage zu beantworten. Warum nicht einen Executor verwenden? und selbst wenn ich dafür einen Handler verwenden wollte, wie?
JRun
Executor ist ein bisschen anders. Um es zu verwenden, müssen Sie den Thread erweitern und im Lauf die Datei static.metohd prepare.of der Looper-Klasse aufrufen. Nachdem Sie die statische Methodenschleife aufgerufen haben, wird eine Warteschlange erstellt, und Sie können eine Handlerbin-Reihenfolge verwenden, um Anforderungen weiterzuleiten und Ergebnisse zurückzugewinnen
Blackbelt