Förstå Android Core: Looper, Handler och HandlerThread

förstå Android Core: Looper, Handler och HandlerThread

den här artikeln täcker Android Looper, Handler och HandlerThread. Dessa är bland byggstenarna i Android OS.

i min egen erfarenhet har jag använt dem i ett mycket begränsat sammanhang tills nyligen. Mitt användningsfall innebar att skicka uppgifter till huvud/ui-tråden, främst för att uppdatera användargränssnittet från någon annan tråd. De andra aspekterna av den flertrådade operationen hanterades genom alternativa sätt som ThreadPoolExecutor, IntentService och AsyncTask.

MultiThreading och task running är gamla ämnen. Java själv har java.util.samtidig paket och gaffel/gå ram för att underlätta det. Flera bibliotek har skrivits för att effektivisera asynkrona operationer. RxJava är det mest populära biblioteket idag för reaktiv programmering och design av en asynkron applikation.

så varför skriver jag om den gamla skolan?

Looper, Handler, och HandlerThread är Android: s sätt att lösa problemen med asynkron programmering. De är inte gamla skolan, men en snygg struktur där en komplex android-RAM är byggd.

för nya utvecklare, är det starkt rekommenderat att förstå principerna bakom dem och erfarna En bör återkomma detta ämne att minnas de mindre detaljerna.

jag har också skapat en video tutorial för detta ämne, och jag rekommenderar att titta på det. Klicka här för att titta nu.

Användningsfall:

  1. huvudtråden i Android är byggd med en Looper och Handlers. Så förståelsen av det är viktigt att skapa ett oblockerat responsivt användargränssnitt.
  2. utvecklarna som skriver bibliotek har inte råd att använda tredjepartsbibliotek på grund av bibliotekets storlek. Så för dem är det bästa alternativet att utnyttja den befintliga tillgängliga resursen. Att skriva egen lösning för det kanske inte alltid får den effektivitetsnivån och optimeringen.
  3. samma argument kan också göras för företag / privatpersoner sjöfarten ut SDK. Klienterna kan ha olika implementeringar, men alla kommer att dela de gemensamma android framework API: erna.
  4. att förstå dem fullt ut kommer att förbättra kapaciteten att följa Android SDK och paketklasser i allmänhet.

låt oss börja utforskningen/revisionen med ett frågeformulär.

jag förväntar mig att läsaren har den grundläggande förståelsen för java-trådar. Om du behöver, få en snabb översikt över java Thread och Runnable.

vad är problemet med java thread?

Java-trådar används endast en gång och dör efter att ha kört sin körmetod.

kan vi förbättra det?

tråden är ett tveeggat svärd. Vi kan påskynda utförandet genom att fördela uppgifterna mellan exekveringstrådar, men kan också sakta ner det när trådarna är överflödiga. Trådskapande i sig är en overhead. Så det bästa alternativet är att ha ett optimalt antal trådar och återanvända dem för utförande av uppgifter.

modell för trådåteranvändning:

  1. tråden hålls vid liv, i en slinga via det är run() metod.
  2. uppgiften utförs seriellt av den tråden och bibehålls i en kö (MessageQueue).
  3. tråden måste avslutas när den är klar.

Vad är Android sätt att göra det?

ovanstående modell implementeras i Android via Looper, Handler och HandlerThread. Systemet kan visualiseras för att vara ett fordon som i artikelns omslag.

  1. MessageQueue är en kö som har uppgifter som kallas meddelanden som ska behandlas.
  2. Handler enqueues uppgift i MessageQueue med Looper och utför dem också när uppgiften kommer ut ur MessageQueue.
  3. Looper är en arbetare som håller en tråd vid liv, slingrar genom MessageQueue och skickar meddelanden till motsvarande handler för att bearbeta.
  4. slutligen Thread avslutas genom att ringa Loopers quit() – metod.

en tråd kan bara ha en unik Looper och kan ha många unika hanterare associerade med den.

skapa Looper och MessageQueue för en tråd:

en tråd får en Looper och MessageQueue genom att ringa Looper.prepare() efter körningen. Looper.prepare() identifierar anropstråden, skapar ett Looper och MessageQueue objekt och associerar thread med dem i ThreadLocal lagringsklass. Looper.loop() måste anropas för att starta den tillhörande looper. På samma sätt måste looper avslutas uttryckligen genom looper.quit().

class LooperThread extends Thread { public Handler mHandler; public void run() { Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { // process incoming messages here // this will run in non-ui/background thread } }; Looper.loop(); } }

skapa Hanterare för en tråd:

A Handler blir implicit associerad med tråden som instansierar den via trådens Looper, men vi kan uttryckligen binda den till en tråd genom att passera trådens looper i konstruktören av Handler.

handler = new Handler() {@Overridepublic void handleMessage(Message msg) { // process incoming messages here // this will run in the thread, which instantiates it }};

skicka meddelanden till MessageQueue via Handler kan göras med två lägen:

  1. Message: det är en klass som definierar olika användbara metoder för att hantera meddelandedata. För att skicka ett objekt ställer vi in obj-variabeln.
Message msg = new Message();msg.obj = "Ali send message";handler.sendMessage(msg);

detaljerad översikt över klassen Message finns här: https://developer.android.com/reference/android/os/Message.html

Runnable: en runnable kan också publiceras i MessageQueue. Ex: publicera och köra en uppgift i huvudtråden.

new Handler(Looper.getMainLooper()).post(new Runnable() {@Overridepublic void run() { // this will run in the main thread }});

i ovanstående exempel skapar vi en Handler och ger Looper associerad med huvudtråden. Detta associerar denna hanterare till huvudtråden. När vi lägger in Runnable, blir det köat i huvudtrådens MessageQueue och körs sedan i huvudtråden.

Handler kan meddelandehantering i en mängd olika sätt, som kan hittas här: https://developer.android.com/reference/android/os/Handler.html

att skapa en egen tråd och tillhandahålla Lopper och MessageQueue är inte rätt sätt att hantera problemet. Så, Android har tillhandahållit HandlerThread(underklass av Thread) för att effektivisera processen. Internt gör det samma saker som vi har gjort men på ett robust sätt. Använd alltid HandlerThread.

ett av sätten att skapa HandlerThread är att underklass det och för det mesta kommer du att använda den här metoden.

private class MyHandlerThread extends HandlerThread { Handler handler; public MyHandlerThread(String name) { super(name); } @Override protected void onLooperPrepared() { handler = new Handler(getLooper()) { @Override public void handleMessage(Message msg) { // process incoming messages here // this will run in non-ui/background thread } }; }}

Obs: Vi har instansierat hanteraren när onLooperPrepared() kallas. Så att Handler kan associeras med det Looper.

  1. Looper är endast förberedd efter att HandlerThread ’ s start() kallas dvs efter att tråden är igång.
  2. A Handler kan associeras med en HandlerThread, först efter att den är Looper är förberedd.

annat sätt att skapa HandlerThread:

HandlerThread handlerThread = new HandlerThread("MyHandlerThread");handlerThread.start();Handler handler = new Handler(handlerThread.getLooper());

notera: HandlerThread måste ringa myHandlerThread.quit() för att frigöra resurserna och stoppa körningen av tråden.

jag föreslår att du övar ovanstående koder, så att du kan förstå deras små detaljer.

jag har skapat ett exempelprojekt för postkontorsimulering. Postkontoret är byggt på HandlerThread och kunder kommunicerar med hjälp av postkontoret. En Simulator klass skapar några klient Bots och delegera sin kommunikation till MainActivity, vilket gör det i en levande foder.

länken till detta exempel

jag har också skapat en video tutorial för detta ämne, och jag rekommenderar att titta på det. Klicka här för att titta nu.

Låt oss också bli vänner på Twitter, Linkedin, Github och Facebook.

lärande är en resa, låt oss lära oss tillsammans!

Lämna ett svar

Din e-postadress kommer inte publiceras.