denne artikel dækker Android Looper, Handler og HandlerThread. Disse er blandt byggestenene i Android OS.
i min egen erfaring har jeg brugt dem i en meget begrænset sammenhæng indtil for nylig. Min brugssag involverede at sende opgaver til hoved – /ui-tråden, primært for at opdatere brugergrænsefladen fra enhver anden tråd. De andre aspekter af multi-threaded operationen blev håndteret gennem alternative måder som Threadpooleksekutor, IntentService og AsyncTask.
MultiThreading og opgavekørsel er gamle emner. Java selv har java.util.samtidig pakke og gaffel / slutte rammer for at lette det. Flere biblioteker er skrevet for at strømline asynkrone operationer. Rkjava er det mest populære bibliotek i dag til reaktiv programmering og design af en asynkron applikation.
så hvorfor skriver jeg om den gamle skole?
Looper
, Handler
, og HandlerThread
er Android ‘ s måde at løse problemerne med asynkron programmering på. De er ikke old school, men en pæn struktur, som en kompleks android-ramme er bygget på.
for nye udviklere anbefales det stærkt at forstå principperne bag dem, og erfarne bør gennemgå dette emne for at huske de mindre detaljer.
jeg har også lavet en video tutorial til dette emne, og jeg kan varmt anbefale at se det. Klik her for at se nu.
Use Cases:
- hovedtråden i Android er bygget med en
Looper
ogHandlers
. Så forståelsen af det er vigtigt at oprette et ikke-blokeret responsivt brugergrænseflade. - udviklerne, der skriver biblioteker, har ikke råd til at bruge tredjepartsbiblioteker på grund af bibliotekets størrelse. Så for dem er den bedste mulighed at udnytte den eksisterende tilgængelige ressource. At skrive egen løsning til det får måske ikke altid det niveau af effektivitet og optimering.
- det samme argument kan også fremsættes for virksomheder/enkeltpersoner, der sender SDK ‘ er ud. Klienterne kan have forskellige implementeringer, men alle af dem vil dele de fælles Android ramme API ‘ er.
- at forstå dem fuldt ud vil forbedre kapaciteten til at følge Android SDK og pakke klasser generelt.
lad os starte udforskningen/revisionen med et spørgeskema.
jeg forventer, at læseren har den grundlæggende forståelse af java-tråde. Hvis du har brug for det, så få et hurtigt overblik over java Thread og Runnable.
hvad er problemet med java-tråd?
Java-tråde er kun engangsbrug og dør efter udførelse af dens køremetode.
kan vi forbedre det?
tråden er et tveægget sværd. Vi kan fremskynde udførelsen ved at distribuere opgaverne mellem udførelsestråde, men kan også bremse den, når trådene er overskydende. Tråd skabelse i sig selv er en overhead. Så den bedste mulighed er at have et optimalt antal tråde og genbruge dem til udførelse af opgaver.
Model for tråd genanvendelighed:
- tråden holdes i live, i en løkke via det er
run()
metode. - opgaven udføres serielt af denne tråd og vedligeholdes i en kø (Messagekø).
- tråden skal afsluttes, når den er færdig.
Hvad er Android ‘ s måde at gøre det på?
ovenstående model er implementeret i Android via Looper
, Handler
og HandlerThread
. Systemet kan visualiseres til at være et køretøj som i artiklens omslag.
-
MessageQueue
er en kø, der har opgaver kaldet meddelelser, som skal behandles. -
Handler
spørger opgaven iMessageQueue
ved hjælp afLooper
og udfører dem også, når opgaven kommer ud afMessageQueue
. -
Looper
er en arbejdstager, der holder en tråd i live, løber igennemMessageQueue
og sender meddelelser til den tilsvarendehandler
for at behandle. - endelig
Thread
bliver afsluttet ved at kalde Looper ‘ squit()
metode.
en tråd kan kun have en unik Looper og kan have mange unikke handlere forbundet med det.
oprettelse Looper og Messagekø for en tråd:
en tråd får en Looper
og MessageQueue
ved at kalde Looper.prepare()
efter dens kørsel. Looper.prepare()
identificerer den kaldende tråd, opretter et Looper
og MessageQueue
objekt og knytter thread
til dem i ThreadLocal
lagringsklasse. Looper.loop()
skal kaldes for at starte den tilknyttede looper. Tilsvarende skal looper
afsluttes eksplicit gennem 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(); } }
oprettelse af Handler til en tråd:
A Handler
bliver implicit forbundet med tråden, der instantierer den via trådens Looper
, men vi kan eksplicit binde den til en tråd ved at føre trådens looper
i konstruktøren af Handler
.
handler = new Handler() {@Overridepublic void handleMessage(Message msg) { // process incoming messages here // this will run in the thread, which instantiates it }};
afsendelse af meddelelser til MessageQueue
via Handler
kan udføres af to tilstande:
-
Message
: det er en klasse, der definerer forskellige nyttige metoder til at håndtere meddelelsesdata. For at sende et objekt indstiller vi obj-variablen.
Message msg = new Message();msg.obj = "Ali send message";handler.sendMessage(msg);
detaljeret oversigt over Message
klasse kan findes her: https://developer.android.com/reference/android/os/Message.html
Runnable
: en runnable kan også bogføres i MessageQueue
. Eks: udstationering og kørsel af en opgave i hovedtråden.
new Handler(Looper.getMainLooper()).post(new Runnable() {@Overridepublic void run() { // this will run in the main thread }});
i ovenstående eksempel opretter vi en Handler
og giver Looper
tilknyttet hovedtråden. Dette forbinder denne handler med hovedtråden. Når vi sender Runnable
, bliver den i kø i hovedtrådens MessageQueue
og derefter udført i hovedtråden.
Handler er i stand til meddelelsesmanipulation på en lang række måder, som kan findes her: https://developer.android.com/reference/android/os/Handler.html
oprettelse af en egen tråd og levering af Lopper
og MessageQueue
er ikke den rigtige måde at håndtere problemet på. Så Android har leveret HandlerThread
(underklasse af Thread
) for at strømline processen. Internt gør det de samme ting, som vi har gjort, men på en robust måde. Så brug altid HandlerThread
.
en af måderne til at oprette HandlerThread er at underklasse det, og det meste af tiden bruger du denne metode.
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 } }; }}
Bemærk: Vi har instantieret handleren, når onLooperPrepared()
kaldes. Så det Handler
kan knyttes til det Looper
.
-
Looper
er kun forberedt efter Handlerthreadsstart()
kaldes dvs.efter at tråden kører. - A
Handler
kan knyttes til aHandlerThread
, først efter at det erLooper
er forberedt.
anden måde at oprette HandlerThread:
HandlerThread handlerThread = new HandlerThread("MyHandlerThread");handlerThread.start();Handler handler = new Handler(handlerThread.getLooper());
Bemærk: HandlerThread skal ringe myHandlerThread.quit()
for at frigøre ressourcerne og stoppe udførelsen af tråden.
jeg vil foreslå at øve ovenstående koder, så du kan forstå deres små detaljer.
jeg har oprettet et eksempelprojekt til postkontorsimulering. Posthuset er bygget på Handlertråd og klienter kommunikerer ved hjælp af posthuset. En Simulator klasse skaber få klient Bots og delegere deres kommunikation til de vigtigsteaktivitet, som gør det i en levende foder.
linket til dette eksempel
jeg har også oprettet en videotutorial til dette emne, og jeg anbefaler stærkt at se det. Klik her for at se nu.
lad os også blive venner på kvidre, Linkedin, Github og Facebook.
læring er en rejse, lad os lære sammen!