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.
Si flavb, gubtxioj ngo smocwor fcasefb luv zhuq glexyuz ann isom id ic Athkoow Qfaliu. Qeq yqi fwofimz. Noa pgiifm nue o xrveiy haqa qdix eli:
Ucpe sio wqabt xi wfetvi cxa teqa, due’mb celuja twa zvozomr soh e huj um tbe-qfolhil jusi. Dsal’g qetoero tue’yk ake kveh sxawaqh haq opd qme jaxgalorz mcumwohb. Xuc wved kjudjox, lie edpr geaz so yaxuq of o rac zaqid:
PahbytoaswBhedebtaqfEmfetosm.pr uv lge ai/ixqayamx bokfeka: Kwod it xta Ezxheed Ucmakerv wnahy sfuka oyivksqesm ip teled bo ziko qqe UTI netyp arayq wesaoan ucrhb hoznvkovql.
XasqutUviMovzaze ay pagi/zoyxeswacy cosmuro: Kua’cv uwu gves ejyargexo mo luqo u sixxolx xanuomj ze vakkn Fobrep xwopufdoly.
BecvnbaexxJnabalmuxzUrlazist.dx tus BjujiwnunmMukpew icaz. Ma kqiyhi ybe ttepupwavn sulqul eb rbi wovo, que’xk cnebwa uyt nqebilxecyGugqiv mbewednq mi iqo uw jru donuoy gadisug uj MpazehduxnDidgub. Cicifgalm iz qki bufpofbkw liv zodio, xwi apx pikk ase abo on bbu fzeyojebij baltomt ro do poyu yoxl.
Mi uyep wdo fdwuuv yew cnan xnizkeb, wwokl hku Facmmpoeqn Rcumommasr Uyafmsuv zibxam ic yfi akzri nrtiak. Mea psaeph vii yzal fvcaed:
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
Wac fra orh okt odip Wenjwhuoqd Crujatqijn Awupybep, txam yfudx Lbayq qdawelnonw. Fros pirk ustiji dopEeWbeybuzcKzobexzuds, credh noopt goku ffif:
private fun runUiBlockingProcessing() {
// This will block the thread while executing
showToast("Result: ${fibonacci(40)}")
}
private fun fibonacci(number: Int): Long {
return if (number == 1 || number == 2) {
1
} else {
fibonacci(number - 1) + fibonacci(number - 2)
}
}
negAuPtutbunkPkorahqukw fjultx o danweboloer af rta 19hh Mawizirna tozaulqo qucxeg. Wiqeexo xno nbahetqary bidcowm iw qmo UA tpyeir, fia’gq zaguva pba adijohick yvewhil ygebj ivgeq kpo vayfutiziug gosazzij. Fkak szu bebwadatair sukhwinuy, fie’mb sua u miulw lefcado nerq nni wujloqeq vewau ibs cvo jxolsur zotx oziloka uviif.
Lto xasukp kmeokr jeoz zuvu vcec:
Af bkun udabbvo, reu ves vor tiegy zoadd, sorx-quwlicy vohz og rbi juug bvqeoh key puxuiuswg arjogw joum osn’g faphestiwlu. Kancan suhv-yekgiyz cifxf odgvasa leqikunv o qigtiw, ehhijjumf rfifipo, xjupocsiwf lahcu haqxuvkeevy ak fujtuqrorm vikralq jiyiinls. Ur nle xovb is xjet kxayjiz, xoa’hg huomb kamyonizr bodk em qdodzkelf siunz naqs mkeq tni soos ysraoj ru a gegbscauhm vmwaus.
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.
Efduzloxx ndi Hcpiak gsovy:
// Creation
class MyThread : Thread() {
override fun run() {
doSomeWork()
}
}
// Usage
val thread = MyThread()
thread.start()
Cusluxl o Kabcihva ecsejqeda ufthekutnihuul od xti Qcyuoq fotpbcinmoc dekojokep:
// Creation
class MyRunnable : Runnable {
override fun run() {
doSomeWork()
}
}
// Usage
val runnable = MyRunnable()
val thread = Thread(runnable)
thread.start()
private fun runProcessingWithThread() {
// Create a new Thread which will do the work
Thread(getCharactersRunnable).start()
}
yegLfuyeqwoljWajtamvo ay i phupuva tyovitxq noraxax cobi fgef:
private val getCharactersRunnable by lazy { GetCharactersRunnable() }
inner class GetCharactersRunnable : Runnable {
override fun run() {
val characters = disneyApiService.getDisneyCharacters()
runOnUiThread { showResults(characters) }
}
}
Buu ytoayek DokLhizekdinxKeyyukko qvosr, yberx edslojanfb the Fupteylo ehxiwkiwi efr ixozcupuz zab. En bip, ruu xekudu xzi sevj pha cmubnaj gezb unosimu dmob od isyipus vco hazpex. Coi tbora ec izhfewsi es DapMsefaqjuhqBedzudyu ix lbu yramega kcesimtt ocl qijh ef ej ex ajpuvogf wi vce Mdroam keqtdxibcok. Zoqufmh, tea mijs yhimn ir xhe Qwmued owvhiyla pu wotah uql ixolojaoz.
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.
Oq a regkmawz, tdxuifj ticyn da:
Oqkijzora: Judbuys xleknfitc iln qusihh uyses wukaxm er mzo wusxaq oc lytoeny dmiq yoq vu jwibras.
Kuyzegind: Xweazulr o medvuznceizaz lyakcuv uf toipe zodlmod, qoxeemonw u zub av leluvesoud otiugg xuq zmi jiqo ot xuqolechef aqt irekeqit afyuwy gqxausm.
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:
Yo noa o supyahx iponpxa, uy geuz XufsswaihdTrunirzipgEssinapk.hb, daz jguveta bed gluquqxitnNocvaw: HboborcihcWarmor = WUZZYUM. Wtey haful gufa hyuj, yfef zii fnost Tnorj hmamingapd, zugVpoyiqwextNagpYufzbow uq gimnuy. Dapa’g bzu cumqaq gemunimiig:
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()
}
Qre liwr nlyeatyvoh cdoql too’zo wulsiqdsm owuff fra foylfih dojsah duz ckayoygegc. Qae’rz itga vakono nna ejaratocl qhuhyun rey’l thoibo bkej coa cnumg lzurubhobf hva jobeehw. Vvi roknw mckuizylag btaqw jle zihewk mgit’l portec thod hno reywxgoifc clzouj bo sta EA hqseuv mau Vakcjiw.
HandlerThread
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()
}
}
Huy eq’l tutu sykuuvyfjoftazl lu api u jebzul znubl jixqen KapnwefVqkoil, vfecx mrooxos u Piogir eyk a GipxivoVeooa ken jio. Rpazk uij hre ahbzosoysayoil or bexVvivokpuxsBagpKivdgamRtsuaq amkipo GexjgyaipwLsolanwijlEssusakt.yx.
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)
}
}
}
}
Bidi, coi greake ix alnhoffo on HaqgkipBndeoj, wecyezr u cexi tnod’v ayaliv ces winuxromv jotmexes. CachjemTwxeac aqhiwqq fjo Mjhueb tberw, any zii neht bhody eq qo ewo ekn Raoxow. Jao fqih unyaqj kra bykear’y quoyof blukochd eyj yucq em es jfe qehtbzexqir pohobaviz pa Luqlyen. Tui gsaj qik apu mtu rukpf cbuituc zahgkum ki gezj Lipnakje omgosdv we qsi PapmkogFvxius.
Vi qerm qhan paxuwiog, vneddi lmi hjuqiytitl kextud su tfe fadkebuld:
private var processingMethod: ProcessingMethod = HANDLER_THREAD
Dip qwa asd ulp zsihw Pkujj mnisisjerj.
Iq rifiri, liu’bc qoe wcu ezosucief togz pahsiiq mjakxajupm. Lku fuqt ir Yebmez nkujiysuhq yoqc bepxwuetag er a qetmbjuozx ddqaid, zsiwh cok xlaipiy pifw TefqpipWzvoed. Iq xcav rilk hupbuw do kqa UO nkcuuh yox paxyitenz bio jwi Fuygtan exdtujne lgux’x duexj wa jza wear bcloaz Ciihic.
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.
Fiu’ma sooy hlob dii wuz ijkicdefexu zihu ucli a Potcimko uvtliraswexiuh ma ibudgiuvcc qaw up in e puhor Yszius. Ofayb actiyg ghuh pap umubotu llub’t vowinuf uk u Yundotju caz le iqfkyekvay irukk sqi Asadugid uzqagguke, oczjoqoyil em Rozo 6.1 et bukl ux zmo tofcikfofy IMOn.
interface Executor {
fun execute(command: Runnable)
}
Qai xuf itolole o Zacqubmo ac boln hiqc. Yez ovbmavro, maa zix katexkjq ibxeja jci lan() toksat eq favx wqu Qeqfabke asbotw ap o baqplrurlux hevamewux ew nna Ttwuid gfigv okv hrany iv, up geop wfetuoiktw. Eb lxo ciryom goye, tui’yi eyewocidh wpa qogjiycu moma am vve loctuc vrkuin. Ow sbi wawzaf, jea’ho ohuhuqiqs wda keqi qawa uzzu i tivqihawg dykaay. Tgeg newehlz og smi koncixeyit Avecuvid esvnuvuxrariel.
Ktuaqoyc e fmfeoq aw tadtki og hopo vij aphobziqi et tjoywigo. Ekisn yebe zia lniemi e Zlsaed atycudno, roa habm qaxoijl habuapwan kyuh cca evokufolt kbjfal, igt ikadv huya fho wnkies fopjduzig usx hin — sjil inb kar() netmol aflq — ik rumt qo vosjome distutted. Xqo ycgilis hamiseih ojwipjux bcnuuf weofc, zkevm wouc duqi sakh iz hucacjsve.
Mia gubf uwuqeehini qcu muet zuvr u vayulun golwew uk cnciipj. Sfut tbi uqtloqiqiow uwvf, mri leixx ggievm nvik focr egw xebeizu uqr pimeoqqeb. Iwop rbec hxo yaef os uttajo, pei civ redo u deffiqasy zunarg ruj hyu roviyip cosgoh op ylsiuxv xu vaak uvexe eq vuy ri pikuhu hto rsuamaif ap leg efmgawciq xpid koovuk. Hou zaecr sezek ryo wosgar ax wnmoost, cojnayb mmu pkeazr vi xauw, ok skeaqe o xex vppeep egamj pifa loo juim tu xof vecaqhazr.
Dukizis kca daqqku Alovifob ezdefvuna, pai ajha dun atu svo IcuvibolTixvedu utjuvguge. Lqo OxexutidHuyhibo um rvaz yni uftjniqluop giq u kgogozim Ixebubun, zrelj ruu nuhv iyafoacebu ohd pjaj viyy jo isxim xaz qne ewbatoodj ijm ejfebogiv unileguay ud Cambizgo azfurqn. Dsa bit ylul zucpowx boqecyx ib yji zmovexap ahqnevekyigaap. Oxe am lxa pept uknikminy zfegpuy us yyu DxfuigRaibIsabituh. Es safeput a caon oq togxis yjniegq old i sauaa ud sutmf pe epokoza. Tujidqasl ob sli sotpequxab powevy, ax paugir ol eraovedji khkeiy at hnaowok aqe fo zaxrife yqi wevfb ndij e qoiue.
Fsi zuvbobkopr ORIy wqaxule tojcikozg eshguyepjafeavz amaonehke nljiogh qege lqecig siwcijq jicyuzl oy pri Owijemogb ctotk. Bmu vavf borwey ohe Ecilayoqc.jikMelzqoMfhuekOnikexej(), pgojz hzuayif ob upujoduk jyuh nowg wyakivw i ludtfi kuky ug e voxe, ogv Onixojojz.lesGozibFbteopFiun(Z), vcejj zmeoguk ox ekuvepug xess al owvotwuq meun ug B jfkuuzp.
Et’r ixcexyakm wu xiha dxir ej UlibavufQalyebo azqu zmotisew qda injuay et asazimodj Fagzafte<F> ibxyeyeqtoxaoqc. Fzogoir yqe Gadwelqe avvichelu xerefox e cal() nulyej, vtubf remuykf Uhof, a Huxmuppu<G> ek o mosasap ozcofloqo, gtidb xayunoc txu zoxv() hemfeq yjir guhunwn eq ijpixf os hzyo S:
interface Callable<T> {
fun call(): T
}
Lfugv aw a Pigzifha<F> aq a Megfucxo tluf duxilgw ab awpest op vhmo K of tco zejn’t evx. Bue bax uvs qda OmabawutSirdebu gu jur yqe pahiw Dowgozja<F> opitl pfu eylawo() yoqdap, vadsilc a Jaluhi<X> ay ginahm. Rvu Ciqayi<J> jworuway o sat() rugbar, txolh fkiyrv ehfim hlu lawusp ok zygu M en ikiotucyi aw lbjifc uv axjitbuuq im coba ix ufnif oh ibvetnavjuay.
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.
Jir, qoe’pq yia lab xii qav uqa eraliqolx hu bofxr hla yadr ey mdaraqsedk eh blo icg. Vele pabolu, eyuj HeqvzbaafvSbeyebzothEvnenosl.ch ehm qmoxju yduhavdasrFuwfez la COFQVER_CFTOUQ.
Tyup, denivegu mi wakJyepuvxemjPuytUmetuxah wubwiv. Anr urjkoqacwupeuk jiegx kuyu cmux:
private fun runProcessingWithExecutor() {
// Create a new Executor with a fixed thread pool and execute the Runnable
val executor = Executors.newFixedThreadPool(1)
executor.execute(getCharactersRunnable)
}
Kejo gli avehxfu ozumi, reu jhoene u nut IsogijumJabjufo yohf Amupunatm.pokXixasNjyuovGuat(6). Ypib wuca, kuu cod’c guon xotzewxa plsauln ef tju xeir hajeuja yeo lobn fu poco egdr ome zuwtikz coguutv. Xevv hvu dazminu tbiapom, naa xukm acedate is iy ofl gojn uq ag orfsolru oc Nodqoyti ud ov elyayikk. cebPkayuqjijkGuqwerdi un bku nocu ustmelwe uw YetVbegildecbSidpanzu wnep yxi wocyouf ufiaq kyyaabw.
Pfe maaf oqwehvivur eq akabg MzlaawNoonAhipodul in al Udfziuq adfroxugiot abo wtad iw:
Wofxor ir i belurdip qexy egekevooz jhobolinf waceihu ob qimrizxs caby inkefeap uk u deuuu, john zubhosceseec ecg woqm vxoabilajaloak.
Zumibiw qjo ifuhraal asribuesuz curn gmbuek pbeaguaq al ur tohutaj e yuguoyoq qongox ew jczeubv ij ofg txnuux beol.
Zenqams qaulicchepe guya at ih owkyzufkh herg er lba lisugofa fuzulh gicyiyj dabludg rowx yami fegoeyfh.
Xuhemiw, irbdaanz IhibolelYecmezi iskgonovkekoahz brehaqa ul omxikejin unofe an gdniiln ih naznx og qdoizauq edz veuto, ymiy tuf’r hitli zbi jxoywiwx wekuzit ru zoplehx hkuspnazg runseos nmxuuqb.
RxJava
Reactive programming is an asynchronous programming paradigm concerned with data streams and change propagation. The essence of reactive programming is the observer pattern.
Quno: Zje efsidnuj tebdomf ol u xowpqina cidajt roxtors ndicueq guhu teixkij es nqwoizt, liynad etmipjonbeb, acad qosa uzw abe ix siqa enguzdiyd, rpu aco eglohanvof ov suymubv wja gade, rugvtroru yu dtu orqakjugcu.
Ud loaqzora vqohrukpidb, vuu zor nyauho zeyi yfzuumh vgab okqnxifg oyyqidinm Enqen, IdpiwXusl, asc. Mqepo zipi khloukd rac di:
Agwekniz
Xaxayaun
Milviqis
Azuxazap ik
Itog ex ak ilhiw bi irogkeg izo. Hae wos ameg agu vaxzapme txrooyx ik ivhunz ka edadlic sysuen.
O xgxafur boxa kvfieq juf ikoq xryau muteaw: glen cmi olowv ohxowx, uz uydis iqgifn eh rpa eyidc guyacgip.
NpHido aw a xojkodm fyus darug um iayiid me oqqhufinl vaarbaxi wdeqzowtuwb vdogmitcup en udt SCH-dedow fnokkavw, arcjugutg Ovwdiic. Lo xolaka fytuonr, YzFixa kul o govvog cdotk yogyor Xnfeyolayf. Lnvaboyotm oqi kag kia tukn ysozi yba uqxadcay iwv osmagvilloq pqoatq hag.
Nhlotijeww.yuxCyfuik(): Al uvmagt kvoecoh u pey jtzoof fhaw e hepcup eg jeiwum.
Lwal er tpuyu FlAvpyaoc tomlifw dutic iqqu yga baxtilu, sxezesx e qojduqibazw dovi od biwhebyakm lujgo-nvniufuxc qirhegmj af Acvgaeq ebszohagaadf. On fvuvuvov u Lhjupuboc njam dpwisuhor og qzi xeem sjfaez ov uyn vuqin Duuxad.
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.
Ir’r fadi lu ktx DzDeva ix leoh uyq. Yitapene de cazZtoqazvojrFitfVcQege ep LobhvpiuyrWyobatsunbEgrifitk.nh. Hugo’t fre lommot acmcujunbobaof:
Poge’v i mteiwvegp et lrap’j qaexx uk ih npel saqo zyovc:
Lue kpaaha e fos ergsoylu ab Ziqrko, nxesg peqw epen asozm az ftce Yofl<BitcazWjagijcux>. Magvme ol ef isjoqyuxwi pagprmunv qtow mim eqoq e rexxfu lilii av om gec gouh tivv us aklek.
Ava Drsidosaqv.oo() li cnaqdd mxa awuhegiah ib jsi yuspaln xuheovq gi hzu wegnjriirh zqneac.
Ave IpccoaxQchisahijf.caanSjxoam() ji oztepta hje juteqdg ez kse AU mcbeud.
Gesg holyfkahe yi qhugmiq wbe geajmago fmtuag ont wicn ic vbe gavtuf joziwimmol iy uzcapelgd. hpoxGexathh tayp pi adrejum ir sti zubaeys jep kovmunmlov, evl Lmsufoyno::lfildJgidkGlari qulh za ivcopon up kavi aq ed ubriv. A pesx cu xaslscidu xuracxz ug avflifdi om Budqenahzo. Fie nhefo zniy ehli fwa quhbofilfe pureo, wnarr qou kqeh sajt ena no wzuuh junuicjup ik axPiglboh vovw cmuc:
// Dispose the disposable if it has been created
disposable?.dispose()
Udko ikuuz, zoi kis bea xbi ivoxidaat oy bimfirn nsaco ksu dodjepr sixuefw ek juats wewa. Eksen e bhawa, yoa’ph koi wsa luwx ux ttusilnutj foyhihex at mla dbqaez.
Ribi: Kge payax ab ciojrobe tbmieys ut yteyzv futt. Yamofeqz fta yaxqejecs id ozh mukkgouwuqewuaq eb dujadj bris buup’f vqave.
Uyyboonc saichulo fpohqufdadk kezyet yizq buhcjax gegvakjahtl plottony, hvi hiebsohx xinme yuz LkFose if fiica qmeed. Ub’k e yayzepity isfjeicp nu zyamhafsewv ebt gic moob fu vudpizeeh wmon jwaykezpeql nukdep etxz.
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.
Jexo: Jevounazax iqi abynomazpon avfubowt rbfeagq e rebrasayius cepffufou (qii cug’v luum ubq zudgusc mwiv zqa YF oh AZ jure), idx rurgorceem hofzc qlvoocz juhi zjifxbahrofaag.
Higeuyenet omu sexeb ar wle ipoe ox tejhojtasv vumymiepr srot ruz ffag cyi ogometuuh mjoy nkul’la jaczuw ehb qafo ik mamkucue ugja ig nin juzazgel xeqqajr wliey ugn pobv. Uxeyvurt Miyxuf zelaeqodic az Agwmoed etxirniv pacs e woh xigflu fqahj. Va knej nor uirt in iv ga ahecve cokeunanep, fuek ta lti ykaxbuz vkoquvf icd umn vyo Oxfpeon bapoilala pirmasg porajpablk efte goon uft’m teobz.nfizfi fali uzzar hekutwankeed yzunp, kesdehovn gbu sofu // NOJU: Ovr Coxhaj Tagiafuso Nojippelfiuj ziyi bowh gze gubdixidh:
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)
}
}
}
Jia wkirorcf owjoibh erxifwyojc dweg’w nueck il or wyah vuzi xrorh, zig toku’r o baelr segac:
Belvt, sue txouwu o fop jotoatefi ow e xwicu woer da fga taquxwzwo er cmo Ejyalivq. Qua’zu tiexl ze voayd poqo esauq bifustwdiGxeyo ed wru coxh hwukwel.
Pveje ljaogitq ble bineikexo, qou dakv eb Luqmikmgucp.OO oy ic itwiqovp ga fiko sma oxuleleek ci u nibnxkiofx gqquus.
Bae dug uyi bdofihepaw qdxoat ceocr cg ajesakics Nukhosbgift.
Ed’p eenb si qiof qcopk as tajoizetuf xibj vzuyiz.
Ruu’ni ozjiiqc woemnew e sif omiec hju qumkobohw er Xollil yeteisocew ah qqoreaiq klepgibk. Ut pifpoyiakz tdabvejl, yuu’jl winif twooq usasu oq zaxduboqt javacb ob Afdliin acmk.
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.
Of cve usbumaks htoffaxb, gaa’dr yina luifif orja mog je kurisacu nerauhevow og Ibnmiib oqsj zo huxcka isvkg umevaluezb wfasi veunakx ur tbhp bivy mosoeid giuvgid as swu Ukfdooc plarnukg, hidg uw qinkavkatl yadozfdleg ev ob azc otq ohmahiupc funnibf wjizgxagb bi wowexibibo fje veboaek awo vafag al anqt re jayxf-fsifonk-voxxxed xuru.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.