Alla som försöker Android-utveckling upptäcker vikten av samtidighet. Det enda sättet att skapa en responsiv app är att lämna UI-tråden så ledigt som möjligt, så att allt det hårda arbetet kan ske asynkront med bakgrundsdragen.
På grund av designen av Android, hanterar tråden med endast java.lang.Thread
och java.util.concurrent
paket kan vara mycket svårt. Med hjälp av de låga nivån med Threading-paket med Android, betyder det att du måste oroa sig för en mycket svår synkronisering för att undvika löpförhållanden. Lyckligtvis gjorde folket på Google det hårda arbetet och byggde några bra verktyg för att göra våra jobb enklare: AsyncTask
, IntentService
, Lastare
, AsyncQueryHandler
och CursorLoader
är alla användbara, liksom HaMeR-klasserna Hanterare
, Meddelande
, och Runnable
. Det finns många bra alternativ för dig att välja mellan, alla med sina fördelar och nackdelar.
Många har sagt om AsyncTask
objekt, och många använder det som en silverkula lösning för samtidighet på Android. Det är mycket användbart för korta operationer, lätt att implementera, och förmodligen det mest populära sättet att samla på Android. Om du vill lära dig mer om AsyncTask
, kolla in följande Envato Tuts + inlägg.
dock, AsyncTask
borde inte vara det enda verktyget på ditt verktygsbälte.
För långvariga operationer, för komplexa samtidighetsproblem, eller för att uppnå mer effektivitet i vissa situationer, bör du välja en annan lösning. Om du behöver mer flexibilitet eller effektivitet än AsyncTask
ger dig möjlighet att använda HaMeR (Hanterare
, Meddelande
& Runnable
) ramverk.I den här handledningen utforskar vi HaMeR-ramen, en av de mest kraftfulla samtidiga modellerna som finns på Android, och vi lär dig när och hur du använder den. I en uppföljningstutorial visar jag dig hur du kodar en applikation för att prova några möjligheter till HaMeR.
Följande avsnitt kommer att introducera vikten av bakgrundstrådar för Android-systemet. Om du är bekant med det här konceptet kan du hoppa över det och gå direkt till diskussionen om HaMeR-ramverket i avsnitt 3.
När en Android-applikation startas är den första tråden som genereras av processen processens huvudgänga, även känd som UI-tråden, som ansvarar för hanteringen av alla användargränssnittslogiken. Detta är den viktigaste tråden i en applikation. Det är ansvaret för hanteringen av all användarinteraktion och också att "binda" programmets rörliga delar tillsammans. Android tar det väldigt seriöst, och om din användargränssnitt fastnar på en uppgift i mer än några sekunder kommer appen att krascha.
[UI-tråden] är mycket viktig eftersom den ansvarar för att skicka händelser till lämpliga gränssnitt för användargränssnitt, inklusive teckningsevenemang. Det är också tråden där din applikation interagerar med komponenter från Android UI-verktygssatsen (komponenter frånandroid.widget
ochandroid.view
paket). Som sådan kallas huvudtråden ibland även UI-tråden. - Processer och trådar, Android Developer Guide
Problemet är att nästan all kod i en Android-applikation kommer att köras på UI-tråden som standard. Eftersom uppgifterna på en tråd görs i följd betyder det att ditt användargränssnitt kan "frysa", blir svarlöst medan det behandlar något annat arbete.
Långsamma uppgifter som kallas för användargränssnittet kommer troligen att vara dödliga för din app, och en dialogruta ANR (Application Not Responding) visas. Även små uppgifter kan äventyra användarupplevelsen. Därför är rätt sätt att ta bort så mycket arbete som möjligt från användargränssnittet med hjälp av bakgrundsgängor. Som sagt tidigare finns det många sätt att lösa problemet och vi kommer att undersöka HaMeR-ramen, en av de grundläggande lösningarna som tillhandahålls av Android för att ta itu med denna situation.
HaMeR-ramen tillåter bakgrundsgängor att skicka meddelanden eller posta runnables till användargränssnittet och till någon annan tråds Meddelandekö
via hanterare. HaMeR refererar till Hanterare
, Meddelande
, & Runnable
. Det finns också några andra viktiga klasser som arbetar tillsammans med HaMeR: Looper
och Meddelandekö
. Tillsammans är dessa objekt ansvariga för att underlätta trådhantering på Android, ta hand om synkronisering och tillhandahålla enkla metoder för bakgrundsgängor att kommunicera med användargränssnittet och med andra trådar.
Så här går klasserna i HaMeR-ramarna ihop.
Looper
kör en meddelandeslinga på en tråd med hjälp av Meddelandekö
.Meddelandekö
innehåller en lista över meddelanden som ska skickas av Looper
.Hanterare
tillåter sändning och bearbetning av Meddelande
och Runnable
till Meddelandekö
. Det kan användas för att skicka och bearbeta meddelanden mellan trådar.Meddelande
innehåller en beskrivning och data som kan skickas till en hanterare.Runnable
representerar en uppgift som ska utföras.Med HaMeR-ramverket kan trådar skicka meddelanden eller posta runnbara objekt antingen till sig själva eller till UI-tråden. HaMeR främjar också bakgrundsinteraktioner via Hanterare
.
Hanterare
är HaMeR-arbetshästen. Det är ansvarigt för att skicka Meddelande
(data meddelande) och post Runnable
(uppgiftsmeddelande) objekt till Meddelandekö
associerad med a Tråd
. Efter att ha levererat uppgifterna till köen mottar hanteraren objekten från Looper
och behandlar meddelandena vid rätt tidpunkt med hjälp av Hanterare
associerad med det.
en Hanterare
kan användas för att skicka eller posta Meddelande
och Runnable
objekt mellan trådar, så länge sådana trådar delar samma process. Annars är det nödvändigt att skapa en Inter Process Communication (IPC), en metod som överträffar omfattningen av denna handledning.
en Hanterare
måste alltid vara associerad med a Looper
, och denna anslutning måste göras under sin instansiering. Om du inte ger en Looper
till Hanterare
, det kommer att vara bunden till dagens Tråd
's Looper
.
// Handler använder nuvarande trådens Looper Handler handler = ny Handler (); // Handler använder Looper ger Handler handler = ny Handler (Looper);
Tänk på att a Hanterare
är alltid associerad med a Looper
, och den här anslutningen är permanent och kan inte ändras när den är etablerad. Men a Looper
s tråd kan ha föreningar med flera Hanterare
s. Det är också viktigt att notera att a Looper
måste vara aktiv före dess förening med a Hanterare
.
Samarbetet mellan Looper
och Meddelandekö
I en Java-tråd skapas en slinga av uppgifter som behandlas i följd. En sådan slinga håller tråden vid liv medan den väntar på att ta emot fler uppgifter. En tråd kan bara ha en Looper
och en Meddelandekö
associerad med det; Det kan dock finnas flera hanterare för varje tråd. Hanteraren ansvarar för att bearbeta uppgifterna i kön, och varje uppgift vet vilken hanterare som är ansvarig för behandlingen.
UI eller huvudtråden är den enda typen tråd som som standard redan har en Hanterare
, en Looper
, och a Meddelandekö
. Andra trådar måste förberedas med dessa objekt innan de kan arbeta med HaMeR-ramen. Först måste vi skapa en Looper
som redan innehåller a Meddelandekö
och fäst den på tråden. Du kan göra detta med en underklass av Tråd
, som följer.
// Förbereda en tråd för HaMeR-klassen LooperThread utökar tråd public Handler mHandler; public void run () // lägga till och förbereda Looper Looper.prepare (); // Handler-förekomsten kommer att associeras med Thread Looper mHandler = new Handler () public void handleMessage (Meddelande msg) // bearbeta inkommande meddelanden här; // Starta meddelandekönslingan med Looper Looper.loop ();
Det är dock enklare att använda en hjälparklass som heter HandlerThread
, som har a Looper
och a Meddelandekö
inbyggd i en Java Tråd
och är redo att ta emot en hanterare.
// HandlerThread-klassen innehåller en fungerande Looper public class. HamerThread utökar HandlerThread // du behöver bara lägga till Handler Private Handler Handler; offentlig HamerThread (strängnamn) super (namn);
De Runnable
är ett Java-gränssnitt som har många användningsområden. Det kan förstås som en enda uppgift som ska utföras på en Tråd
. Den har en enda metod som måste genomföras, Runnable.run ()
, att utföra uppgiften.
// Deklarera en Runnable Runnable r = Ny Runnable () @Override public void run () // uppgiften går här;
Det finns flera alternativ att skicka en Runnable
på en Hanterare
.
Handler.post (Runnable r)
: Lägg till Runnable
till Meddelandekö
.Handler.postAtFrontOfQueue (Runnable r)
: Lägg till Runnable
på framsidan av Meddelandekö
.Hanterare.postAtTime (Runnable r, long timeMillis)
: Lägg till Runnable
på Meddelandekö
att ringas vid en viss tidpunkt.Hanterare.postDelayed (Runnable r, lång fördröjning)
: Lägg till Runnable
till köen som ska ringas efter en viss tid har gått.// posta en Runnable på en Handler Handler handler = ny Handler (); handler.post (new Runnable () @Override public void run () // uppgiften går här);
Det är också möjligt att använda standardgränssnittshanteraren för att lägga in en Runnable
kallelse Activity.runOnUiThread ()
.
// posta Runnable med användarhandboken Activity.runOnUiThread (ny Runnable () @Override public void run () // uppgift att utföra);
Det är viktigt att komma ihåg några saker om Runnable
s. Till skillnad från en Meddelande
, en Runnable
kan inte återvinnas - när jobbet är klart är det dött. Eftersom det ingår i ett standard Java-paket, a Runnable
beror inte på Hanterare
och kan kallas på en standard Tråd
använda Runnable.run ()
metod. Detta tillvägagångssätt har emellertid ingenting att göra med HaMeR-ramverket och kommer inte att dela några av dess fördelar.
De Meddelande
objekt definierar ett meddelande som innehåller en beskrivning och några godtyckliga data som kan skickas och behandlas via Hanterare
. De Meddelande
identifieras med en int
definierad på Message.what ()
. De Meddelande
kan hålla två andra int
argument och an Objekt
att lagra olika typer av data.
Message.what
: int
identifiera Meddelande
Message.arg1
: int
godtyckligt argumentMessage.arg2
: int
godtyckligt argumentMessage.obj
: Objekt
att lagra olika typer av data När du behöver skicka ett meddelande, istället för att skapa en från början, är det rekommenderade sättet att hämta en återvunnen enhet direkt från den globala poolen med Message.obtain ()
eller Handler.obtainMessage ()
kommandon. Det finns några olika versioner av de metoder som låter dig få en Meddelande
enligt ditt behov.
En gemensam användning av Handler.obtainMessage ()
är när du behöver skicka ett meddelande till en bakgrundstråd. Du kommer att använda Hanterare
associerad med den här tråden Looper
för att erhålla en Meddelande
och skicka den till bakgrundsgängan, som i exemplet nedan.
int vad = 0; String hej = "Hej!"; // Hämta meddelande i samband med bakgrunden Trådmeddelande msg = handlerBGThread.obtainMessage (vad hej); // Skickar meddelandet till bakgrunden TrådhanterareBGThread.sendMessage (msg);
Det finns massor av coola metoder på Meddelande
klass, och jag råder dig att titta närmare på dokumentationen.
skicka meddelande()
alternativPå samma sätt som hur vi kan posta Runnable
s, det finns flera alternativ att skicka Meddelande
s:
Handler.sendMessage (Meddelande msg)
: Lägg till en Meddelande
till Meddelandekö
.Handler.sendMessageAtFrontOfQueue (Meddelande meddelande)
: Lägg till en Meddelande
till framsidan av Meddelandekö
.Handler.sendMessageAtTime (Message msg, long timeInMillis)
: Lägg till en Meddelande
till köen vid en viss tidpunkt.Handler.sendMessageDelayed (Message msg, long timeInMillis)
: Lägg till en Meddelande
till köen efter en viss tid har gått.De Meddelande
föremål som skickas av Looper
bearbetas av hanteraren med metoden Handler.handleMessage
. Allt du behöver göra är att förlänga Hanterare
klass och åsidosätta denna metod för att behandla meddelandena.
public class MessageHandler utökar Handler @Override public void handleMessage (Meddelande msg) switch (msg.what) // hantera "Hello" msg fall 0: String hej = (String) msg.obj; System.out.println (hello); ha sönder;
HaMeR-ramen kan hjälpa till att förbättra din Android-applikations samtidiga kod. Det kan tyckas förvirrande först i jämförelse med enkelheten hos en AsyncTask
, men haMeRs öppenhet kan vara en fördel om den används korrekt.
Kom ihåg:
Handler.post ()
metoder används när avsändare vet vilka åtgärder som ska utföras.Handler.sendMessage()
metoder används när mottagaren vet vilken operation som ska utföras.Om du vill veta mer om tråden i Android kan du vara intresserad av boken Effektiv Android-tråder: Asynkrona Behandlingstekniker för Android-applikationer av Anders Goransson.
I nästa handledning fortsätter vi att utforska HaMeR-ramverket med ett praktiskt tillvägagångssätt, genom att bygga en applikation som visar olika sätt att använda denna parallellram för Android. Vi skapar den här appen från grunden och försöker olika möjligheter som kommunikation mellan Trådar
, pratar med användargränssnittet, samt skickar meddelanden och inlägg Runnable
s med förseningar.
Ses snart!