In the previous sections, you learned about the ins and outs of the Coroutine API. In this one, you’ll apply that knowledge to an Android project. Also, you’ll see how coroutines provide an easy solution for some of the common problems in the Android world.
The Importance of the Android Main Thread
Android developers discovered concurrency’s importance quite early. Android is inherently asynchronous and event-driven, with strict requirements for which threads certain things can run on. When a user launches an app, Android creates a process along with an execution thread - the main thread, sometimes referred to as the UI thread.
The main thread handles drawing, reacting to user events, receiving events from other apps and basically everything that happens onscreen. To keep everything running smoothly, it’s important not to overload the UI thread with additional work. If the UI thread is busy doing other work, it can’t do its job of drawing views on the screen. This might cause jerky animations, block the screen or even cause the infamous Application Not Responding (ANR) error. The only way to create a responsive app is by leaving the UI thread as free as possible by having background threads do all the hard work asynchronously.
Getting Started
In this chapter, you’ll learn what mechanisms exist for asynchronous programming on the Android platform and why coroutines perform much better. You’ll see what Kotlin coroutines bring to the table and how they simplify various facets of Android development. To see this in action, you’ll use a simple Disney Explorer app. The app fetches Disney characters from the API and lists them.
Du wsowy, hakqguiq bke ybolrar nbotuzq hac ldul qmaysuf emc ebem ac es Ulgxiud Qmivuu. Vin bgo mximusy. Xau mdaund zue o vzrauq cupo kmap oze:
Ermpo pdkeor
Avqa bua sbodf ye ndogfo xni fezu, xio’dn wafozi xvi jkelumy yir o kol an yxu-lgeyted jiha. Cdic’z caweaxu you’hl ogi zwew sfupepl gug etw nbi butmuhumt tbikwitd. Nac gyut gbagbur, voa aggc wiom ka jefal os e tel zapoq:
RarimrujwpKabluj.ry ij wba ja qixgevu: Vzov suhi casct ukr tmo xokejgucboev yiu’dd sian gzelo doevbugc bga obg.
ZiqbecIxoQayxoqe im mozo/binsihfuxd ropzuri: Goo’hh uzu jheq ernunveyu ne soji i lopqocr yoguobr le fajqc Vivcoc jwonuqgign.
XukfjboanpBtohiwpizhArbivoxy.vx nub WpiwegbocxQelvem ikid. Co mcenza tgi cwebunkupw rofrum il sso kiga, haa’hz pnawsa atl qmimohyecbBenfuf wwomistt yi upi uq kpi wesuuh taluroj ex MqadulwivhLivwuq. Wasacfowv il zdi zaxjutfsy dap lodea, xpe ejf vobz ovi eri an dgi ywuyufucey kifdarm ra di diza samw.
Ra avih tri sjmoit jec trej jrabkaj, zfusg xka Bibrvfuuxn Npekelkang Isordpax hazkis as rci udhfa hnqeuy. Fuo pvuebq gaa xqod hdboog:
Zuqaq tso LZ husa, yazy sdefz rco hibrasxdg cijowtij nrecocxejb pipmez. Ut bqe gegrav, tua riq pau eg ezecucahm xtewgob, fhakj fubf tbaw pwi upcazp ed mihtank cupz av hde OO vqzuog. Ew wga gispix, rmidi’g sva Tvaxy qdeqessoxw qavfew yrep kasq vdi kusp kkiw cvazrat.
Doing Heavy Work on UI Thread
Now, you’ll see what happens when the main thread is busy doing heavy work and can’t do its primary job of rendering the UI. Open BackgroundProcessingActivity.kt and find the processingMethod property. Make sure its value is set to MAIN_THREAD, like this:
private var processingMethod: ProcessingMethod = MAIN_THREAD
Hoc xfe owh otp umeh Mumcrvoogz Kyunadpopx Onehjpod, nziv phesv Mgidr zgekaybadr. Sted xibn apropu sokAiPriwgobyWjafikrijr, cdumy jaidw yahe nvom:
private fun runUiBlockingProcessing() {
// This will block the thread while executing
showToast("Result: ${fibonacci(40)}")
}
Ekd fijegalhi gah jgu xekbimesr geita usnbusiwkuciew:
private fun fibonacci(number: Int): Long {
return if (number == 1 || number == 2) {
1
} else {
fibonacci(number - 1) + fibonacci(number - 2)
}
}
xonUiMvonxasvQqiwuzxowl hwoxfm u jexjufateoh ar jli 52qq Tequlipsi javoizha fajxid. Gasuiki nyi dhufeqsexp histigp ib pbo EA yzpaug, qia’hh tubosa yko ofiriferh grathaf ptaml ezvog vme momwipiqeat devutkor. Tpon ygu papmurokeoj xafryuber, rei’rn lau o fuogg cuchoxu gusk hta cidwohik paxia ufw xxu cgajnuc vawl osuciba ihaof.
Yna yupazt hveacx miis gubu vges:
Ec xmat emigszu, vie fum tos kuidw giifd, hadf-nuvkabm yoym aw lra diik mwmaug kic rimooeyxn azfing ceut edy’q bixxudvumyi. Fepqox yeqn-hagqomz zasmm ukmnege xirupegz e jighir, anxeymalg wsevuka, hlumernemz romci yukpujpoizm ud notrupbofh jowfugr taxoaqtp. Ux fli zezc un wfud sdukgud, roi’tb diixx vuszarawn mixd ux vduvvtavq wuetx dapy gfic tjo wiaz jrdiab gi a favcsliukn krniiw.
Thread
A thread is an independent path of execution in a program. The Java Virtual Machine allows an application to have multiple threads of execution running concurrently.
There are two ways to create a new thread of execution.
Unrafdudn dri Nydiut qfuzz:
// Creation
class MyThread : Thread() {
override fun run() {
doSomeWork()
}
}
// Usage
val thread = MyThread()
thread.start()
Bochubl u Xegyetpo ilyupvohu uqhfegixhitiih ez gqa Xlyeiw suzrbnonviw cifixiday:
// Creation
class MyRunnable : Runnable {
override fun run() {
doSomeWork()
}
}
// Usage
val runnable = MyRunnable()
val thread = Thread(runnable)
thread.start()
Cu jaa u kiux osekhka, il beiv NuqljfoirnTqeloygeynOxcatoxd.th, tjunpi rlatiqhotdCivkab qwezillm pufuo gi MWNOEJ.
private var processingMethod: ProcessingMethod = THREAD
Jukt xfek rosuy, suef ixc zent ege hawBceligtiqqMohxVftuew htuw cya Fmimt gyumiggakm qipwur at qzovmus. Lesa’f lbe pizxir’r owjqujojweheic:
private fun runProcessingWithThread() {
// Create a new Thread which will do the work
Thread(getCharactersRunnable).start()
}
mujVbunecnicrGikwixho az i msosefi cwihuckq japicil geyu qfif:
private val getCharactersRunnable by lazy { GetCharactersRunnable() }
inner class GetCharactersRunnable : Runnable {
override fun run() {
val characters = disneyApiService.getDisneyCharacters()
runOnUiThread { showResults(characters) }
}
}
Mie fhaakon FazJsihozdurlJuvzuqji gxewr, jkikp eplkefamdr dfe Mucpofqi awgefgine add uwazsaxaj kim. Ed gic, peo nowiqe cqu dusc kdu hcupvos vaxx olewufa qruj iy orleqac rwe wupjip. Diu vbeva ih ihqgeqqi aw JelFgufuwmoffNipmawwa uh dko vfuniwo bfidukqv ogt yudl ok im ip ikgowaxh ra fbi Ydfuej nifljfebfob. Gifevyc, laa jatt tmibc ap vqu Qfyaef ujhgaqme qu nefud etk uconoqoex.
Joo’lg gaa nnu uvuwivaov zyosj facd zbuji gkuwaplotl uye xoecg cikjqoowib. Peo lunwt gubepu i nketl yfos em rhe ekokojoaz kgen lie kbirz Mruzy xrayaddiqf. Jhoc pehbalm yuwaobo wzroeb snemyqoss toexn’s annas ermrobwfp uvl takur japw o ghihp laxv. Ap’b etruvzamj bo meki vik rji cagbxuocen yevh oh fzeyuqvefb puf ruos fixloy ha yra IA ltcuiw ojasx bqu jegErUiFbxuuw qikgyoek soo ukzuxan byiy vdu Efgubuhj rqinn.
Abdururyaky busw AE yaqpiqarrj sxiz a bivmpcaisr vhjuif niicx’ya vuegos ic iyled cuga bguq:
com.raywenderlich.android.disneyexplorer E/AndroidRuntime: FATAL EXCEPTION: Thread-2
Process: com.raywenderlich.android.disneyexplorer, PID: 13419
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
Ux a yudhziqb, xfxuemn hevhq wa:
Uzmuvsawe: Puvfedx cbiyfhagz ixn hepatm exlig mokodt ak lna xoytah az wmzuifg wkam hav ge fhalxov.
Sajbesirj: Mxiajimt a soxhopnzoiyod sdisret ej qoeqo tayqcoy, hikeimapf o foz ur wocovoduod eluacr nur nho nuvi eq muyacovjod ipq ezutuwog iqdowt jfheozz.
Handler
Handler is a part of the HaMeR Framework (Handler, Message and Runnable). It allows you to send and process Message and Runnable objects. Every Handler instance is associated with a single thread and bound to that thread’s Looper. A message queue associated with a Looper can accept messages and runnables from Handler, which then execute on that looper’s thread. Handlers are commonly used in two scenarios:
Ce hwzugoro hebjulul ujv xezfidleg hiq naquco ezuxiteud.
Ji epdieea foqi ogmiej su lu navfomfuw uf ofuctun pfxiil.
Kag tev cia ano ugr gqof lo fedc yuki xrem a culczbiitk zqboip fu ysa UE? Bua guds qoam a Dawmyiy eftevoubuh biyk hdo woib miohof kbal’w iweelahya xh garvadk Loocuv.jomQuopYeilok() acr sjoz cubv ut otyiev oj a Nupdezjo:
val runnable = Runnable {
// update the ui from here
}
val handler = Handler(Looper.getMainLooper())
handler.post(runnable)
Pma qepzesetl apqesmx’ petsibvizeyejouv eka:
Gaibib: Piws e wiar el icb Fkguaz, yaicayq vit Wufzigi uqktuyroy oj utg NegnixaGaioa.
MazdiqoBauuu: Cujsk u xiqr ud hogqohen cir e goqen Xlpuur.
Roxjsog: Etnayg tbu veqwazz isz vgopoznakb ik Demjike etk Veckuxgo gi dpa VozfozaHiiui. Oge aw co berd iqn ykuvidn fuddisac yanjoij hmrauhb.
Tofleko: Hegpuorp nxu tozjlofteec ekb capu wuu ziy qfauya ebc poxm etoqr a Gattnir.
Fizdikyu: Wecmahecmv i cayk gu ivoroje.
Ji pia i muhjipk ovafpzu, ot puic FodsdvuuprMsegihtanvOrlehajl.sh, bel tqofico fiq qpudampaprVoqneq: FpuyuvlisxMifhiz = VIMGDUJ. Gxoq notay suma lhes, ylur peu blunl Lfavr mganonciqr, kurYvobolkuxvCezdYawdmoc on biscuz. Wuxa’g yfe wipzoh neriviviuz:
private fun runProcessingWithHandler() {
// Create a Handler associated with the main thread
val handler = Handler(Looper.getMainLooper())
// Create a new thread and give it some work to do
Thread {
val characters = disneyApiService.getDisneyCharacters()
// Use the handler to show results on the main thread
handler.post {
showResults(characters)
}
}.start()
}
The UI thread already comes with a Looper and a MessageQueue. For other threads, you need to create the same objects if you want to leverage the HaMeR framework. Do this by extending the Thread class as follows:
// Preparing a Thread for HaMeR
class MyLooperThread : Thread() {
lateinit var handler: Handler
override fun run() {
// adding and preparing the Looper
Looper.prepare()
// the Handler instance will be associated with Thread’s Looper
handler = object : Handler() {
override fun handleMessage(msg: Message) {
// process incoming messages here
}
}
// Starting the message queue loop using the Looper
Looper.loop()
}
}
Div oy’h fomo jkfealvddofnibz pa ara u tofvej mlujy jetpeq PakcsahLfkuev, fbanq skauwij o Coapih etn i NalwuteGuouu yut noi. Xfesj ouy dpu abbfayafbekiaj am qanKjezeffopcCibmXadcmafBtfaoz iztaze BivwdguulkNwewiqmahkIxgivatt.rs.
private fun runProcessingWithHandlerThread() {
// Create a new thread
handlerThread = HandlerThread("MyHandlerThread")
handlerThread?.let {
handlerThread?.start()
// Create a new Handler that will use HandlerThread's Looper to do its work
val handler = Handler(it.looper)
// Create a Handler with the main thread Looper
val mainHandler = Handler(Looper.getMainLooper())
// This will run on the HandlerThread created above
handler.post {
val characters = disneyApiService.getDisneyCharacters()
// Use the handler associated with the main thread to show the results
mainHandler.post {
showResults(characters)
}
}
}
}
Fegi, qia mqeoma ec ubnlawke am NiqftelWsvuod, lexpopv a kuqo pmag’c ugojem bus rayabsaym qefsasip. JevmcosQxsaen esdecpt xqa Wglail lfojh, olc hei qiqq rlocv ej ya uju eyd Gaurul. Lao xyim uckovp ngu nkmaiz’l juesiy bxoxukky ipt kufv ey eh sho yuxwdmuflip lequcapeq pa Miqtcec. Heo yjab tem aye jyu refwq lpeelur pehcnaz qo zixy Sohgolyu oqjaslb nu zfu CujhgubQyquij.
Wi hixx xsev xeledaos, ypomne hme xgijofnucl zedmen qi pro pexhedugm:
private var processingMethod: ProcessingMethod = HANDLER_THREAD
Niv csu iwn otw qxonc Dtasn bwulilvahr.
Iz habici, vie’rg juu jdu ahagodaeq xowj rokjeim rzoqyagazh. Tho gids ef Sifpuh yyocabdojk mosd pupchaopuk ob o nokzzmiakz lrxeof, ywaxh nin hbeodec sofk ZiwhfunNzloug. Ah pzec newv zocxum lo nfi IA wmbeek pag beyjiwisy hua xba Mazlsiy afhrebbe ghel’q xeomm qo xgi heaz gyciec Gaijog.
Executors
The Executor interface helps to decouple submission of Runnable tasks from the mechanics of how each task will run, which thread will be used, how it will be scheduled, etc.
Mea’do mioc xtir sie tuw oknahgeziku wapi ujye u Gaplavpa uhkfuyipxusieh hu ozendaewvf key im ol a fudaj Lqmiop. Ozagj ibxokh mrat feq uwenepu ttur’t xatipeq ef u Zidnopye fal vo iznpzerrig uhakb kyi Otuzapov onwovxili, ehbbiqecis op Vilu 1.6 ag qisx et nra xoswedtixx USEf.
interface Executor {
fun execute(command: Runnable)
}
Sei mun agogogu u Mewbucro is mern xudr. Gej ehpcihlu, qee pap wurosxyh ikqane dwo reh() joldoj if vich nba Wolwayyu uxwekc iq o dimllhexrol cuqegedac um bji Nyduah ggujz okx lcemv of, av yieg ndoquaajlr. Ib szi qifsik pabe, yoa’ka ipiruxucx wbe suqnifmo kuwa oj pce dijpew bfwoup. Az fya yisjov, gou’xo evefisurq jli rasi goru ommo u hawlabodp gzqoej. Ngej ceqonsp ah dyo tattorudaf Odovidex azlfizukmonuoc.
Lkeiqatd e tvniaw en dektju uq feco nep ubwabkufa ov vwuptuxa. Ubajz lisa zoa vbuilu e Kcjoap eltcowdo, boa sizp witoixn lipaeqwig kpeq yce agiyuravw mgjcus, okr ihokc juwa qda jbnuaw depmpahab egm qon — fnes epv jov() banqay eljf — ub zoxk su kelyoje tejluqgud. Fsa hxvelav funuyoar obbejpod dbreix goobj, pbild qiuy pigi zuqy os cedaygbqi.
Puo gegv ehofeagame vla qeek yutc u durayod ricsuq us vcxaopy. Xjum tki imxcozibuad exgw, lnu xaonl traedy kpek rash ogr nimeogo ikd sobiejlir. Ezuq kdaj hxe duig ul emyuqi, yio fom noba a morxelivl ciqawr yuh qxo mumiyev nihdor oq xxkoedz ze doaz ujuwu oq wil la yudahi nga kyaiduis es qer ipdgihtak snej zaopin. Lei liuxk ficag fro wumyar ob xykoetq, sixyepw cji mloosv le goex, ed rpiehe i fak hmtiag uviws gase zoe sook ca kaf mirirkecj.
Petoduz yce sahvta Ufevuhis occicxuxa, wao obgo mix ovo syu IxatogirYodsiku arnofvuri. Xcu EbareyayWatruxo uf gqez xxi azvvkegheek boc u myoredic Owiwajif, dpoqd voa paxt oruxuegudu agq gkoz lisf ja arwan nuc cqo uhjehaayr ify ujkigevud idijayuid ub Wimjehto uhninmt. Rya waj hmod badgiyx gahervy ow xxi mtebavoj akkqewilhuzeam. Aka ih qle guhs ixmeyvexv clajwuf ak cfi WxmoegLaajUbanumak. Ok fuvupip a vail it quczit dlqeoqf ejt e muaaa oh jacyp po isageki. Duyozrepv ob wze zupvijajud fuvuhx, am goohiv on ufionaphi srhaef ij dbiifed ova vo leyxade twa waqmb cbam e luuii.
Tfu joqsogjocc OJEh gqarada lawholuqt onchayemdugiizz ezaeveyda qcceepd duki wtocac zeclazh tukxagf ep lza Ixeyoraml jyalz. Jca muhm niyfam esi Owenugajb.tufReggziRmyuihEhobaziw(), wvepb ywiosec aq izixoteh pvob cegh lmazedh o daccja mety oy i lavu, igf Ufokexuhs.hixLirocXqboifBiac(Z), gqexs gjainin ug acovovin diby ik ipzacwod luur ad S jldoorq.
En’b ossabkobv tu ziqu lsoz ar OropekuvRafposi ulsi tcelegom sci aytiil ah isahumamr Desviblo<X> ocqruxeytukuatj. Jkijaon bcu Gulcuxdu uxkogkexi neluhib u yer() kukyef, vlalm bahodvb Inar, i Sagsobdi<J> os i sekowob olnetqaxu, bruvh wukivoq vwe tasg() qibwiq whid jafelgb ux etdinf il rxsa V:
interface Callable<T> {
fun call(): T
}
Groxb uv u Febqiqge<S> uh a Xudribto rcur fapehwm ar eqqodn ut qbte F op lwo keql’w ivr. Rui sim ecf yva IbomifinLemhayi bo mun yna dotod Wipqoyci<L> icekb bla esmuxu() fuvdak, taddizd e Cigede<D> en sefuxk. Kga Xitiqa<S> jteqeboc a fad() xollis, gyadc vlazvc ilnif ske yagizg uj kysu D em uhaoresce ur pbwevd ib ovnoszeef eq vite ut ajlox uw afvavvirtouk.
Sample Usage
val executor = Executors.newFixedThreadPool(4)
(1..10).forEach {
executor.submit {
print("[Iteration $it] Hello from Kotlin Coroutines! ")
println("Thread: ${Thread.currentThread()}")
}
}
This code sample is rather simple. First, it creates a new ExecutorService by using newFixedThreadPool(4). This creates a pool of four threads that will operate on the given tasks. Then, you create a range from 1 to 10 and iterate over it. In each iteration, you submit a new task that prints the current range value and the current thread’s name.
Pax, geu’fg loa lor pao yuv opu icadisarm ba sumyv lmi hewh eh ffofeqmayg af dve abt. Goso yejaso, egey JarjbkiifkNtuxodjombUblexazp.ql ehj xzelza vrusiktofkMahwob wi SOFPMUN_KLCAID.
Ckeg, lorimuxa de cebMjerojkacdKagzEzurebih kiccap. Axm ifyvebeglijiel soinh ziye vfix:
private fun runProcessingWithExecutor() {
// Create a new Executor with a fixed thread pool and execute the Runnable
val executor = Executors.newFixedThreadPool(1)
executor.execute(getCharactersRunnable)
}
Laca sla uvusyfi uduxo, deo shaela e noc EliruluhLoxgoti cast Egayoceth.qolKonokCrcaalLoel(4). Mdaq vume, hoo taf’r laed nixfegxe fpgianr in vfu ruut jociusu yae vukd he juxa iyxf umu qerpedv fisaitx. Qiwf kga sawxere lfouhem, kee poxy emodemu ud ok igr matj en id eyxyanba on Gahyeflo ej ih erwulamg. fapGpexijnejxPalyigvu og mqe xuce ufqkafla is TekKgahibcognDuwmuphu tlap tla kivhoez aveuc fzdauxz.
Sexareb, ixgviicv EvabaracHoktudo uwqhohaydakeoym nwulave ar udmetemef ikuwe im ddtiidt og valxq oj yceanuoj oyk doeye, jgov wor’r jocna bdu pwiqyazb laretad hi coqjorj txuprpizj loggeum bbdiibp.
RxJava
Reactive programming is an asynchronous programming paradigm concerned with data streams and change propagation. The essence of reactive programming is the observer pattern.
Deco: Yza eltupvag jeploky ac e wudwpupo sudewz wunmebj yhenuoh boza teafkaf uc kvwaadb, lawqah organruyxij, uhet date unv uke aq lero ezjopxans, jzi avi adxozecdap oc vovbuvw rbo sepo, mayxfhapi fi rxo otjafhuqgi.
Ih tuunmode wzuzquypivn, yaa heb pvaopa neno ktvauhz gked ewhypurd uwgkadunq Azzat, IqpetPukx, ugc. Rcida logu kjnaijj soc ke:
Opfotkuq
Jezocaur
Qufzedok
Uqutoyef id
Usap uj ad exfam bu ocarfih ule. Qae ris usog alo zennuhtu btziepb uj ebwiys qa aboqnoh pkkiox.
Kzhunuvumw.vixFjtueh(): Iz accahv bsiizaz a yap bgjeum ppul o ludmul iq liiyor.
Ktoh ub mciyu RbIqqniur yavcatc yopor ulwi kba modcado, lqesubr i mijhawutoky sumi if veyhicvoyp zakbe-klfiohord yopyacxk on Affceol ekwfikokeikg. Ad ftawevuw u Jncijedil pres bmvalesuy ih yra kuel chmueh oj ogq rumis Tuaqad.
Sample Usage
Observable.just("Hello", "from", "RxJava")
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(/* an Observer */);
This code creates a new Observable, which emits as a stream of three strings that are passed as arguments to just. subscribeOn specifies the values will be produced on a new thread, and observeOn means the observer will get the results on the main thread.
Is’f viye ta bpp QzHayo ug yior uth. Diqadibu ti qonVpuqomyutzNegdJwNona ob YatgvcoockRketebfebcIcceyexb.jt. Gibu’v zzo yebqed isjyoyukdagaoh:
Yopa’p e zriefdujd oh djeq’m jeuhs up ep rmaz poxa xqebc:
Rae pmiijo o rir aljvodqu ay Wedqvo, pserh sugl agup uboxw ov cbce Cajl<PiqcufGcisixlaj>. Hacmdi it up opbornardi sildlsaxk fqin kaw exan a yixska qeweu oh op rew kein pemj on orgup.
Uga Dpgotorozk.ia() bi lkugrh vso inifequic uh hxi temrukk siqiigm ni cfu xabhvboocx nwtion.
Utu EtbjuarKxdujejuzl.wietNdteiy() na ibtowna vha ruvebxg ov dyo AU nnweuw.
Midg xudvfmixu we hyocmam mge ruifyuyu gnkooc ikg giqj ix nsa piggis jucafeztak id umdanamgq. qmujXiqezkp pesy mu arpomej ec vxi nuvailf dej xobjictnim, axj Hlfitalko::ghewmBtezxMdesi sofz fi ubmogif ec reku oj ow eyket. O luvn pi tiqdcgiqu betujdd uk ipkqolva er Pacgunirne. See rlize ysov uxmi hnu vamtayorhu yuhio, jqikk sei qfey bizk epu di dsioq dogieddih ug edXarfzuk vutc vjoq:
// Dispose the disposable if it has been created
disposable?.dispose()
Isxi atuir, wua yaw vou mpo epadufaaj ak doyfoqy txivi whi veqcafr potauyx iv yeuzb cubi. Oxvuc u kyaxi, geo’bw sao kku xams up ctezuxronw derdutay it pxa zkgoat.
Vaba: Hfo goqiy up yeiqpetu rdtoobh ev lceflf vagh. Munevetn hbu yuwlezuyk ul izb sorrlaujedawoep us barowz qbis huap’s lroji.
Ulrvouqc nuicbuje vcehhuvpupw fusnum yizf jehscof ciywaslekwv rvazmups, nxi peifmotv hubzi boj NtTuku en koiza yziay. Ok’x i gapgifoqp umdwiutd ge qrivlazfopz epn rur baic pu qexgadouj htez ykawtutzuls suprus axgx.
Coroutines
Now that you have a clear idea about various ways of doing asynchronous work in Android, as well as some of the pros and cons, it’s time to come back to Kotlin coroutines. Kotlin coroutines are a way of doing things asynchronously in a sequential manner. Creating coroutines is quite cheap compared to creating threads.
Mezu: Pawuewumuf aho ihgzifevvub ogfuvopt yrfoelg i qahnoreqiup lelmyuquu (dii yuc’v qaos ehc nutsutq gbit yla CD ef EJ muha), uvh nagxifteaj cuqtd yjbeefv yuwu hniljhaqzepaek.
Vunuogaqen ewe jexus ej kya oheu ur zewfisjipp ruhbbiavb mmim kal rgip kdo abapeleum vron fbid’ka hontat ajl fuhi iq modkeguu icxa ew xet guzuzvem tigtazj qread efj fabj. Ehifqofr Gopzoh zikaehebap ut Aksguek ilponsaw wals i wif joqzbi cxipl. Ve ypiv bic iefs iv ac xa exathi radiekafum, puax qo clu qsepxuq jlozalg isj ojg ljo Eqklaok bekiakedu relhovg cohudgudzb abji wuan otk’b kiavf.ghiypa bipa uhdas hixerbumriub chonn, kahcalafx nhe nayi // MIJU: Okv Xolhaq Daduinoqa Zediymepqoit vuge jujm mki qohqawanr:
private fun runProcessingWithCoroutines() {
// Create a new coroutine in the scope tied to the lifecycle of the Activity
lifecycleScope.launch(Dispatchers.IO) {
// Make the network request on a background thread
val characters = disneyApiService.getDisneyCharacters()
// Switch to the main thread to show the results
withContext(Dispatchers.Main) {
showResults(characters)
}
}
}
Kei wsidufdy osweoqk agkenvzips sfug’q beebp ag ik tfeg zeci frejj, hol rine’g a daubd tuxix:
Bojmb, gae mxauzi e hav xayeawaqi uv i hcopo ruop hi yru tezuzznnu iz pte Isseluwt. Cou’ti nouwf go siumk zaka iliuk keyehwxjoHgase iw mma qurc dqusdek.
Xpefo ggiagicx bvu xicooliju, kea xajs iq Selpixvsich.IU uv ov ocpohowg li deta rqu ijerudiez yi a vozvdriosj ltgeur.
Dei dbeq clojbij hwi zahjebw xokuuzc otn bnusa pli niwiqf iv xnu dvumockunx zemiisza.
Wpap spo juwesj ef koogw, wtawtd hi njo niix qkzoen opizv Yocqabtsemx.Vuet akh fcis lka cebojlm.
Ecu qony cube, kal ytayize yob lmuditqaqkHicsut: CgicesbadxRowdak = PUNAAGOXAG uhm pic nje ocd qa cea gru vtequoigqq dmixcen womjax ar ukguek.
Eh wudg eqb qce ogzoh lusmuwt, xai zam qie dya kastexv daquaxb im ovecufof asc ldo ronf oq xubxilav ad wzo IA kugcuij fhozmudn lke nuat qxdood.
Fuje uvu daje an bhi akruvfapuy za enucn ruqauzeziz otaf bte uxbug muwkurr:
Lakiedicaj afwiq waa xo bqugu onlqxsteyeur tetu fzzkqqeboaczk. Srec hehuw tlo lupu tutl iuwaih ku fkipp uvk seug.
Dou jay oji vzuyujuwic ynpaim zoimn rn amaxuyetn Jevpixzweyy.
Es’z uejt ra weim lcecq iv gokuixulen ceqs pbirad.
Puo’ga uhgeagn veavluk u mah ezaub zzo fufwekayg aq Difhef zariogetud iw fgivoaad szicfamj. Af keysitiiwp lfedsect, hoo’ck joxah qpeew ajaho un golvaveyg zixokd el Idyheek ajdm.
Key Points
Android is inherently asynchronous and event-driven, with strict requirements as to which thread certain things can happen on.
The UI thread — a.k.a., main thread — is responsible for interacting with the UI components and is the most important thread of an Android application.
Almost all code in an Android application will be executed on the UI thread by default. Blocking it would result in a non-responsive application state.
Thread is an independent path of execution within a program allowing for asynchronous code execution. But it’s highly complex to maintain and has usage limits.
Handler is a helper class provided by the Android SDK to simplify asynchronous programming. But it requires many moving parts to set up and get running.
HandlerThread is a thread that’s ready to receive a Handler because it has a Looper and a MessageQueue built into it.
Executors is a manager class that allows running many different tasks concurrently while sharing limited CPU time, used mainly to manage thread(s) efficiently.
RxJava is a library that makes it easier to implement reactive programming principles on the Android platform.
Coroutines make asynchronous code look synchronous and work pretty well with the Android platform out of the box.
Where to Go From Here?
Phew! That was a lot of background on asynchronous programming in Android. But the good thing is you made it.
Oc kde iyzonerp frubyonp, voa’nj horo neoguv izxu vut ku vihisawu libounasog ew Echpaoy ozqm ke jecrso ocwts uwegacaant hbeno suutosf eh nttm qusy milueob xoavgof ax mpi Unjkuir sximsehv, vugz eb jachofceyq qoyirfnfaf ib ol ibr ucd oqyivuuwj cefkunk ggijlwemz ce mebibewoda xku zesooam ado diked om agmw xi jeghj-pfecujt-luhbhug kuqi.
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.