Jeder, der Android-Entwicklung versucht, entdeckt die Bedeutung der Parallelität. Die einzige Möglichkeit, eine responsive App zu erstellen, besteht darin, den UI-Thread so frei wie möglich zu lassen und die harte Arbeit asynchron von Hintergrund-Threads ausführen zu lassen.
Aufgrund des Designs von Android können Threads nur mit der java.lang.thread
und java.util.concurrent
Pakete könnten wirklich schwierig sein. Die Verwendung der Low-Level-Threading-Pakete mit Android bedeutet, dass Sie sich um viele knifflige Synchronisationen sorgen müssen, um Race-Bedingungen zu vermeiden. Glücklicherweise haben die Leute bei Google die harte Arbeit geleistet und einige großartige Tools entwickelt, um unsere Arbeit zu erleichtern: AsyncTask
, IntentService
, Lader
, AsyncQueryHandler
und CursorLoader
sind alle nützlich, ebenso wie die HaMeR-Klassen Handler
, Botschaft
, und Lauffähig
. Es gibt viele großartige Möglichkeiten, aus denen Sie wählen können, jede mit ihren Vor- und Nachteilen.
Über das ist viel gesagt worden AsyncTask
Objekt, und viele Leute verwenden es als Silberkugel Lösung für Parallelität auf Android. Es ist äußerst nützlich für kurze Operationen, einfach zu implementieren und wahrscheinlich der beliebteste Ansatz für Parallelität auf Android. Wenn Sie mehr darüber erfahren möchten AsyncTask
, Schauen Sie sich die folgenden Envato Tuts + Beiträge an.
jedoch, AsyncTask
sollte nicht das einzige Werkzeug an Ihrem Werkzeuggürtel sein.
Bei lang andauernden Vorgängen, bei komplexen Parallelitätsproblemen oder zur Erzielung einer höheren Effizienz in bestimmten Situationen sollten Sie eine andere Lösung wählen. Wenn Sie mehr Flexibilität oder Effizienz benötigen als AsyncTask
bietet, können Sie den HaMeR (Handler
, Botschaft
& Lauffähig
) Rahmen.In diesem Lernprogramm werden wir das HaMeR-Framework, eines der leistungsfähigsten Parallelitätsmodelle für Android, kennenlernen und erfahren, wann und wie es verwendet wird. In einem anschließenden Tutorial zeige ich Ihnen, wie Sie eine Anwendung programmieren, um einige Möglichkeiten von HaMeR auszuprobieren.
Im folgenden Abschnitt wird die Bedeutung von Hintergrundthreads für das Android-System erläutert. Wenn Sie mit diesem Konzept vertraut sind, überspringen Sie es und gehen Sie direkt zur Diskussion des HaMeR-Rahmens in Abschnitt 3.
Wenn eine Android-Anwendung gestartet wird, ist der erste Thread, der durch den Prozess erzeugt wird, der Haupt-Thread, der auch als UI-Thread bezeichnet wird und für die Handhabung der gesamten Benutzeroberflächenlogik verantwortlich ist. Dies ist der wichtigste Thread einer Anwendung. Es ist dafür verantwortlich, alle Benutzerinteraktionen zu handhaben und die beweglichen Teile der Anwendung zusammenzubinden. Android nimmt dies sehr ernst und wenn Ihr UI-Thread länger als ein paar Sekunden an einer Aufgabe arbeitet, stürzt die App ab.
[Der UI-Thread] ist sehr wichtig, da er für das Versenden von Ereignissen an die entsprechenden Benutzeroberflächen-Widgets zuständig ist, einschließlich Zeichnungsereignisse. Es ist auch der Thread, in dem Ihre Anwendung mit Komponenten aus dem Android-UI-Toolkit (Komponenten aus demandroid.widget
undandroid.view
Pakete). Daher wird der Haupt-Thread manchmal auch als UI-Thread bezeichnet. - Prozesse und Threads, Android Developer Guide
Das Problem ist, dass fast der gesamte Code in einer Android-Anwendung standardmäßig auf dem UI-Thread ausgeführt wird. Da die Aufgaben in einem Thread sequenziell ausgeführt werden, bedeutet dies, dass Ihre Benutzeroberfläche "einfrieren" kann und nicht mehr reagiert, während andere Aufgaben bearbeitet werden.
Langfristige Aufgaben, die auf der Benutzeroberfläche aufgerufen werden, sind für Ihre App wahrscheinlich fatal und es erscheint ein ANR-Dialogfeld (Application Not Responding). Selbst kleine Aufgaben können die Benutzererfahrung beeinträchtigen. Daher ist es die richtige Vorgehensweise, so viel Arbeit wie möglich aus dem Benutzeroberflächenthread mit Hintergrundthreads zu entfernen. Wie bereits erwähnt, gibt es viele Möglichkeiten, dieses Problem zu lösen, und wir werden das HaMeR-Framework untersuchen, eine der Kernlösungen von Android, um dieser Situation zu begegnen.
Das HaMeR-Framework ermöglicht es Hintergrund-Threads, Nachrichten zu senden oder Runnables an den UI-Thread und an andere Threads zu senden MessageQueue
über Handler. HaMeR bezieht sich auf Handler
, Botschaft
, & Lauffähig
. Es gibt auch einige andere wichtige Klassen, die mit dem HaMeR zusammenarbeiten: Looper
und MessageQueue
. Zusammen sind diese Objekte dafür verantwortlich, das Thread-Management auf Android zu vereinfachen, für die Synchronisierung zu sorgen und einfache Methoden für Hintergrund-Threads bereitzustellen, um mit der Benutzeroberfläche und mit anderen Threads zu kommunizieren.
So passen die Klassen im HaMeR-Framework zusammen.
Looper
Führt eine Meldungsschleife für einen Thread aus, der die MessageQueue
.MessageQueue
enthält eine Liste von Nachrichten, die vom gesendet werden sollen Looper
.Handler
ermöglicht das Senden und Verarbeiten von Botschaft
und Lauffähig
zum MessageQueue
. Es kann zum Senden und Verarbeiten von Nachrichten zwischen Threads verwendet werden.Botschaft
enthält eine Beschreibung und Daten, die an einen Handler gesendet werden können.Lauffähig
repräsentiert eine auszuführende Aufgabe.Mit dem HaMeR-Framework können Threads Nachrichten senden oder ausführbare Objekte entweder an sich selbst oder an den UI-Thread senden. HaMeR fördert auch Hintergrund-Thread-Interaktionen über Handler
.
Handler
ist das HaMeR-Arbeitstier. Es ist für das Senden verantwortlich Botschaft
(Datennachricht) und Post Lauffähig
(Aufgabennachricht) wendet den an MessageQueue
verbunden mit einem Faden
. Nachdem die Aufgaben an die Warteschlange übergeben wurden, erhält der Handler die Objekte vom Looper
und verarbeitet die Meldungen zu gegebener Zeit mit der Handler
mit ihr verbundenen.
EIN Handler
kann zum Senden oder Posten verwendet werden Botschaft
und Lauffähig
Objekte zwischen Threads, sofern diese Threads den gleichen Prozess verwenden. Andernfalls muss ein Inter Process Communication (IPC) erstellt werden, eine Methodik, die den Rahmen dieses Tutorials sprengt.
EIN Handler
muss immer mit einem verbunden sein Looper
, und diese Verbindung muss während der Instantiierung hergestellt werden. Wenn Sie keine angeben Looper
zum Handler
, es wird an den Strom gebunden Faden
's Looper
.
// Handler verwendet den Looper-Handler des aktuellen Threads. Handler = new Handler (); // Handler verwendet den Looper-Handler-Handler = new Handler (Looper);
Denken Sie daran, dass a Handler
ist immer mit einem verbunden Looper
, und diese Verbindung ist dauerhaft und kann nicht einmal geändert werden. A Looper
's Thread kann Assoziationen mit mehreren haben Handler
s. Es ist auch wichtig zu beachten, dass a Looper
muss vor seiner Verknüpfung mit einem aktiv sein Handler
.
Die kooperative Arbeit zwischen Looper
und MessageQueue
In einem Java-Thread wird eine Schleife von Tasks erstellt, die nacheinander verarbeitet werden. Eine solche Schleife hält den Thread am Leben, während er auf weitere Aufgaben wartet. Ein Thread kann nur einen haben Looper
und ein MessageQueue
mit ihr verbundenen; Es können jedoch mehrere Handler für jeden Thread vorhanden sein. Die Handler sind für die Verarbeitung der Aufgaben in der Warteschlange verantwortlich, und jede Aufgabe weiß, welcher Handler für die Verarbeitung zuständig ist.
Die Benutzeroberfläche oder der Haupt-Thread ist die einzige Art von Thread, für die standardmäßig bereits ein Thread vorhanden ist Handler
, ein Looper
, und ein MessageQueue
. Andere Threads müssen mit diesen Objekten vorbereitet werden, bevor sie mit dem HaMeR-Framework arbeiten können. Zuerst müssen wir eine erstellen Looper
das beinhaltet schon ein MessageQueue
und befestigen Sie es an den Faden. Sie können dies mit einer Unterklasse von tun Faden
, wie folgt.
// Einen Thread für die HaMeR-Klasse vorbereiten LooperThread erweitert den Thread public Handler mHandler; public void run () // Hinzufügen und Vorbereiten des Looper Looper.prepare (); // Die Handler-Instanz wird mit dem Looper des Threads verknüpft. mHandler = new Handler () public void handleMessage (Message msg) // hier eingehende Nachrichten verarbeiten; // Starten der Nachrichtenwarteschlangenschleife mithilfe des Looper Looper.loop ();
Es ist jedoch einfacher, eine sogenannte Helper-Klasse zu verwenden HandlerThread
, die hat eine Looper
und ein MessageQueue
in ein Java eingebaut Faden
und ist bereit, einen Handler zu erhalten.
// Die HandlerThread-Klasse enthält eine funktionierende öffentliche Looper-Klasse. HamerThread erweitert HandlerThread // Sie müssen nur den privaten Handler-Handler-Handler hinzufügen. public HamerThread (String-Name) Super (Name);
Das Lauffähig
ist eine Java-Schnittstelle, die viele Anwendungen hat. Es kann als eine einzige Aufgabe verstanden werden, die auf einem Computer ausgeführt werden muss Faden
. Es gibt eine einzige Methode, die implementiert werden muss, Runnable.run ()
, um die Aufgabe auszuführen.
// Deklarieren einer ausführbaren ausführbaren Datei r = new Runnable () @Override public void run () // die Aufgabe geht hier hin;
Es gibt mehrere Möglichkeiten, ein zu posten Lauffähig
auf einen Handler
.
Handler.post (lauffähig r)
: Ergänzen Sie die Lauffähig
zum MessageQueue
.Handler.postAtFrontOfQueue (lauffähig r)
: Ergänzen Sie die Lauffähig
an der Vorderseite des MessageQueue
.Handler.postAtTime (lauffähig r, long timeMillis)
: Ergänzen Sie die Lauffähig
auf der MessageQueue
zu einem bestimmten Zeitpunkt angerufen werden.Handler.postDelayed (lauffähig r, lange Verzögerung)
: Ergänzen Sie die Lauffähig
an die Warteschlange, die nach Ablauf einer bestimmten Zeit aufgerufen werden soll.// Posten eines Runable auf einem Handler Handler Handler = new Handler (); handler.post (new Runnable () @Override public void run () // Aufgabe geht hier hin));
Es ist auch möglich, den Standard-UI-Handler zum Buchen von a zu verwenden Lauffähig
Berufung Activity.runOnUiThread ()
.
// Posten mit dem UI-Handler lauffähig Activity.runOnUiThread (new Runnable () @Override public void run () // auszuführende Aufgabe);
Es ist wichtig, einige Dinge zu beachten Lauffähig
s. Im Gegensatz zu einem Botschaft
, ein Lauffähig
Kann nicht recycelt werden - sobald die Arbeit erledigt ist, ist sie tot. Da es Teil eines Standard-Java-Pakets ist, a Lauffähig
hängt nicht von ab Handler
und kann auf einem Standard aufgerufen werden Faden
Verwendung der Runnable.run ()
Methode. Dieser Ansatz hat jedoch nichts mit dem HaMeR-Framework zu tun und teilt seine Vorteile nicht.
Das Botschaft
object definiert eine Nachricht, die eine Beschreibung und einige beliebige Daten enthält, die über gesendet und verarbeitet werden können Handler
. Das Botschaft
ist mit einem gekennzeichnet int
definiert am Message.what ()
. Das Botschaft
kann zwei andere halten int
Argumente und ein Objekt
verschiedene Arten von Daten zu speichern.
Nachricht.was
: int
Identifizierung der Botschaft
Nachricht.arg1
: int
beliebiges ArgumentNachricht.arg2
: int
beliebiges ArgumentMessage.obj
: Objekt
verschiedene Arten von Daten zu speichern Wenn Sie eine Nachricht senden müssen, anstatt sie von Grund auf neu zu erstellen, empfiehlt es sich, eine recycelte Nachricht direkt aus dem globalen Pool mit der Message.obtain ()
oder Handler.obtainMessage ()
Befehle. Es gibt verschiedene Versionen dieser Methoden, mit denen Sie eine Botschaft
je nach Bedarf.
Eine häufige Verwendung von Handler.obtainMessage ()
ist, wenn Sie eine Nachricht an einen Hintergrund-Thread senden müssen. Sie werden das verwenden Handler
mit diesem Thread verbunden Looper
a erhalten Botschaft
und senden Sie es an den Hintergrund-Thread, wie im Beispiel unten.
int was = 0; String hallo = "Hallo!"; // Abrufen einer mit dem Hintergrund verknüpften Nachricht Thread-Nachricht msg = handlerBGThread.obtainMessage (what, hallo); // Senden der Nachricht an den Hintergrund Thread handlerBGThread.sendMessage (msg);
Es gibt viele coole Methoden auf der Botschaft
Klasse, und ich rate Ihnen, sich die Dokumentation genauer anzusehen.
Nachricht senden()
OptionenÄhnlich wie wir posten können Lauffähig
s gibt es mehrere Optionen zum Senden Botschaft
s:
Handler.sendMessage (Message msg)
: füge hinzu ein Botschaft
zum MessageQueue
.Handler.sendMessageAtFrontOfQueue (Message msg)
: füge hinzu ein Botschaft
zur Vorderseite des MessageQueue
.Handler.sendMessageAtTime (Nachricht msg, long timeInMillis)
: füge hinzu ein Botschaft
zu einer bestimmten Zeit in die Warteschlange.Handler.sendMessageDelayed (Nachricht msg, long timeInMillis)
: füge hinzu ein Botschaft
in die Warteschlange ein, nachdem eine bestimmte Zeit vergangen ist.Das Botschaft
Objekte, die von Looper
werden vom Handler mit der Methode verarbeitet Handler.handleMessage
. Alles, was Sie tun müssen, ist die Erweiterung Handler
Klasse und überschreiben Sie diese Methode, um die Nachrichten zu verarbeiten.
public class MessageHandler erweitert Handler @Override public void handleMessage (Nachricht msg) switch (msg.what) // Handle 'Hello' msg case 0: String hello = (String) msg.obj; System.out.println (Hallo); brechen;
Das HaMeR-Framework kann dazu beitragen, den gleichzeitigen Code Ihrer Android-Anwendung zu verbessern. Es mag auf den ersten Blick verwirrend erscheinen, wenn man es mit der Einfachheit eines Systems vergleicht AsyncTask
, Die Offenheit von HaMeR kann jedoch von Vorteil sein, wenn es richtig eingesetzt wird.
Merken:
Handlerpost ()
Methoden werden verwendet, wenn Absender wissen, welche Vorgänge auszuführen sind.Handler.sendMessage()
Methoden werden verwendet, wenn der Empfänger weiß, welche Operation ausgeführt werden soll.Um mehr über Threading in Android zu erfahren, können Sie sich für das Buch Effizientes Android-Threading: Asynchrone Verarbeitungstechniken für Android-Anwendungen von Anders Goransson interessieren.
Im nächsten Lernprogramm werden wir das HaMeR-Framework mit einem praktischen Ansatz erkunden, indem wir eine Anwendung entwickeln, die verschiedene Möglichkeiten der Verwendung dieses Android-Parallelitäts-Frameworks demonstriert. Wir erstellen diese App von Grund auf und probieren verschiedene Möglichkeiten aus, wie etwa die Kommunikation zwischen ihnen Fäden
, mit dem UI-Thread sprechen sowie Nachrichten senden und posten Lauffähig
s mit Verzögerungen.
Bis bald!