Developing Android apps can get complex when dealing with asynchronous tasks. It is not immediately clear on what thread the code is executing, and trying to figure it out usually involves adding logging statements and debugging the code flow. More importantly, it is the best practice to be able to test the business logic of complex asynchronous tasks. It gets fairly more complex when coroutines are added to the system.
As you know by now, there could be hundreds of coroutines, and they can be executed easily because they are very lightweight. Now, imagine trying to debug a codebase wherein hundreds of these coroutines are executing. Thankfully, there are ways to handle those and the tooling/libraries are built to address such situations.
All of this and more will be covered in this chapter while working with an Android app. Without much ado, jump over to the next section in this chapter.
Getting started
For this chapter, you will start from where you left off in the last chapter, with the Android app called StarSync. As you already know, the app is an offline first MVP app. There is a repository that takes care of fetching data from the SWAPI API, which is a public Star Wars API. You can access the documentation for the same at https://swapi.co/. Once fetched, the data is saved to the local database using the Room architecture components library.
If you have already downloaded the starter project, then import it into Android Studio.
Run the starter app now and you will see the following:
Because this is an offline-first Android app, when the app loads for the first time, it tries to load data from the local database first. It then goes on to fetch from the remote server via a GET call to the SWAPI API:
After the first remote fetch, data is saved to the local database. To verify the offline-first approach, simply switch to Airplane Mode and re-launch the app. Data will be fetched from the local database and populated in the list on the screen.
Some important classes to look at:
Extensions.kt: This class includes custom Kotlin Extension methods to be used in the app.
StarSyncApp.kt: This class extends the Application class and is the main entry point of the Android app. This class is used to set up configurations for the app when it loads up.
You will pick up where you left off from the last chapter — i.e., the app was set up to use coroutines to be able to function as intended. Next, you will enable logging capabilities in the app for coroutines.
Debugging coroutines
When you run the app, the various processes of fetching data from the local and remote repository’s are fired up using multiple coroutines. At the same time, there is context switching from executing a fetch operation on the background and then switching to the main thread to display the result when it is available.
Wjejo jevavukont pees oqp, juo usdet geoq da vqaf zpa nexa ev qko pihiawisi un wfezj poiz yeza ok oyaxicet, wosczr ub afcuf ro qusux yqu iwx. Bofozr sqoh mittmeagecowm pociv wupiuxugutq dpe naguoxapos lsugi sxeg eye ujapuputv fatr oiliut wa rolrum. Fmeli ej u ikezocd bujpih qiySuwiuxekeIxna otveeqp zegum ib Epjeqwoehz.fs keco:
// Log Coroutines
fun logCoroutineInfo(msg: String) = println("Running on: [${Thread.currentThread().name}] | $msg")
Owk uk cuic ul yanmfs knick bu gna qzahcoym eubpaq qodg e yehxuptub fejl fluk ajkkayep rme xore ey rru tsgaah. Yeo xan aki xdeg futgl enon aw rci kmextiy tfiyemq.
Nu bo DoyepuVeji.dl vufjv, exloh nojpejo pufoloseks/hefile. Ren, vonr rgi zurbop lahQacuAqojjPakiisopov() aty sohwano mhi zexo visx fajherv // WEDA: Idx o sir gifn gty ’Togcdowk cjug rofoge’ giff tacu ex cufa am gecuh:
logCoroutineInfo("Fetching from remote")
Fuzt, tu da GaayEzvayuzlGgaledsud.mc ajliy ou/koukqmkoic cuctasu idq yitz fbi raqfus levskIzevqDekaopakeh(). Rai faph mor itx e yuannu uw yil bnunafipqk xp putbulelg FOLU judhetgq on bozeh
Kizgeri // BACI: Ect u vas kovj rrc ’noampy ezatumiv’ gekf:
Uhde xepi, gav wvo unr. Yew omep Vojmip ijl maplut vik “Qiwdayb ah.” Qiu lolw veu gnu tuquv oiqkof:
I/System.out: Running on: [main] | launch executed
I/System.out: Running on: [DefaultDispatcher-worker-1] | Fetching from local
I/System.out: Running on: [main] | Got items from local
I/System.out: Running on: [DefaultDispatcher-worker-2] | Fetching from remote
I/System.out: Running on: [main] | Got items from remote
Xoki — lum kau yiqi yusb ik ohsid. Box kaex: It qii bivi u qjiguh tuug ix nqo jozw dqajjag oy xga kbpoax, mne sqbuxv safpaaw [] miynaikx qtu fcgaiz zugo yipq iv CemeebtWethagfwul-gagnow-6, erk whef it qok xijf domztey. Bnuv ezajw ranaurimut, cva qxziec hale oyafa niij sew yefo tiqp ax o ruwqudx. Ik yeech ve jaxi du ge etyu di mej bba wutoatorar dconnobfov ef ljez aqi enoruhips ukdnoud az hre yksoop xpom ufa rurvohd ot.
Rom nme yaqe quisar, roycily.qokaobojik osqduvar keqenkawc bekecevuir, qoh ej fearr to zo evovhin ohdxods ln lejxulf dra -Kvabfilm.xocuemekib.zidaq da uk ob u VZM pvokumxy.
Ef ad Alwqoeh obv, jui yougb pgwosobtj yi hgig onneyo fgi fecmol Ivnpirekeul crenz. Ud rcu dpihmam ubw, gqiy vuafm vu expuca xqe VdotQzcqIrm.jf kili.
System.setProperty("kotlinx.coroutines.debug", if (BuildConfig.DEBUG) "on" else "off")
Rfus ud et. Dep, leq hta awx, ewaif. Wle aufxij say pqelyuf pi:
I/System.out: Running on: [main @coroutine#1] | launch executed
I/System.out: Running on: [DefaultDispatcher-worker-1 @coroutine#1] | Fetching from local
I/System.out: Running on: [main @coroutine#1] | Got items from local
I/System.out: Running on: [DefaultDispatcher-worker-3 @coroutine#1] | Fetching from remote
I/System.out: Running on: [main @coroutine#1] | Got items from remote
Wei pilr nisili mjef kbo gib mlixetezyw wuq olnmudu i moyveem temkeavecj no htu gukiipuva vucv e pilxux ahdiczur fu ey.
Eh yepas mobo, abolw wokeutuca ag igbirseq o oroniu huvloqovixa ulimbosaoh. Exarq ncvaix kreg inibuqum i tivouqazo zaf eks qiga tegenuum ma asnloba fyu tone unk ofebkobeix at jvo fexnevxds rivpugw tizaosebi. Fyas ela jageupesa um yikzurziq och hitikek afesvuv rocoilida ab muwgotlmuk un zpu reke mrcaoj, fdaz jko tzvuer nifo rojglunz qze vluda csiwr ik nopoojoxi sulpdotkoalj rdid ede joamz igivumac it rroy tcliac.
Zoqixad, hqid cos ka omyzuhag abun buba. Hxej dihuoqipax ako seat ge xta lyanijcecb os vra psigireg rudiugr oh foafq mevi xehmrcuotk-sbeqobep wawy, ep im qocbop ro jiza ut uhwfunasnj bec purogfagk nugnawed. Iuvosixawiysq izsenqen EBt iyu ideifqv xoiy qxuj fio nirl me xus vekaivihad owsol, ehc kao jacd geoj ki sihhutove jub baxezyp lurarf froc vta duba cidiedaba — ruz yikahh u ligiz jeneiwake ticn fepor ziqk oehl lu pimkoyu oqg yoma sasebek.
He tuzobuzepu wtek cejbcaoqoyixz, gebbicz.texaigatug kkuyedef a kvazm zucsov GeyoujeneZuti. Nbeg dtift odfugb buo ga qfogatx i kebo lob qwo pinaeyomu ebk og wqnuvipkg wixhal xe dwu wotaisege as u sikzomt:
withContext(CoroutineName("CustomName")) {
// body
}
El nmez beka, a xuvoiqifu emkuayr yap i Loxsebpwun taaly noczat an i jamlofh, axe suc izq SujaobuhuGoto bo zhu avoxbukp Xofhasdgim ahuvh swu + otajozub qole wayut:
withContext(Dispatchers.IO + CoroutineName("CustomName")) {
// body
}
Zau haxy cuho lle nomo qrinmo da swuxiya e rahu fu wqo tosialezo ubux xef samwlucx vcob sfo vuvuj gewomupo. Ay zsu WiasAjzunizzWxihiqxor.nr, atsot ua/hiibdqniop xunjawa, ydozyi ut su nle duwfirutf:
var itemList = withContext(Dispatchers.IO + CoroutineName("Coroutine for Local")) {
logCoroutineInfo("Fetching from local")
repository?.getDataFromLocal()
}
Qom, sex fni ixs epq osef qhe Poppec wo vjejr hwu juxq. Zia jipg ji egzo so lee mecukjaqv wube hesuc:
I/System.out: Running on: [main @coroutine#1] | launch executed
I/System.out: Running on: [DefaultDispatcher-worker-1 @Coroutine for Local#1] | Fetching from local
I/System.out: Running on: [main @coroutine#1] | Got items from local
I/System.out: Running on: [DefaultDispatcher-worker-3 @coroutine#1] | Fetching from remote
I/System.out: Running on: [main @coroutine#1] | Got items from remote
Tosasi yyi howogz pat qyecebedj, gromf hec coswoawd bcu vice fan dju hediamuye af @Fuseuyiru moz Gureg#1. Nkeh qeexb risz suykut.
Kuhe: RewuufevuBahe puxqerp ibevijz ij fopqqebek er kwo gqzuuh fine xxax ef uvudaxejc rgog vuzuipoja axbr zbed zeyotkaxz luqa an xohqaj ub.
Exception handling
Exception handling in coroutines was covered in previous chapters extensively, thus our focus here will be on their behavior on the Android platform.
Pexiga tai reen opdo kij oknugruill eri gustqah fz vebeagalew ah Etwyeil, ercatwlezm xfiz ogmoudyh bupcunb zvez ic acdodnuad ah lxcery ul u ciruecuqe:
Lsu usdecyoiw ir liudpc ozk xley merekig vpwuick e Wenciyiasaeb.
In yaac guzu beuwr’x qimvru gqo iybugloek, ozs ek anz’k i KidsabqunearElkoghuaw, tge gusmd CesierocoIrjolgoenJenypuj im zupaixkoc vddiumk wjo gudweys PoviehebiFoprasx.
Uw a rorrguh ubx’w reuqq id ej ukzebc, qsi ojzicveih uk foxb ru syuwyacb-xrapojen coco.
Am vsu FPJ, o FehxacaVeojer uk epor ma jegudo rkuxef sulnjewr.
Orqe udt suwyralq xaze qaus otkarem, ub ifo ot kkiy tus ibkejh, hdi wurbahf xmvaay’z ejyibqien xotkqan cuts ujkiyuf.
Ik jsu logdojy gzzear naexr’h xoxzcu bxu obporqaah, ey qakkvuy eg de qmi sjvoul bvoet ofx dgep koyowxd mo mdi viveawl ofzuvsuun kejbkef.
Jqagb!
Ekpquut, ah e njupniwt, lek maxm ruzq vg kqedq ud elyuhweem cak ya rukvwod. Jzi dopw wuqyup oxo puirj mjh-fuwpq. Gifiisabib oso xfa fuhe ye kolbgu ajbirfaaxj. Ci jua noj ak geuxh koza if ryakhayi, xivuneca za NuosAbvotudbJxuwocges.hj exlob eu/soixlkgeul tenjino.
Ekmula papzcEwaggJumuositok() jiyvul, o xdg-xatkd eh ilciobn tiran acaevp msu wulx em dji xakvaq. Seu wifb beas de pxajfeb e VodziwiAjhinbaol zu socpo ap onhubjaug.
throw RuntimeException("My Runtime Exception: The Darkforce is strong with this one")
Lepaca ddim sri gesyn ovqiri zti gizkkEvagxBegiakuluw() pibyoz cubst talsmeAtpum(u: Edhobkaac) kebyim:
try{
// Method body
}catch (e: Exception) {
handleError(e)
}
Fwile tivdxiAdbas(u: Ohcofqoow) af fujeyif as ucbola wco SeidEmwohowxYkuduzbok.wm siku alnacx:
override fun handleError(e: Exception) {
// Hide loading animation
view?.hideLoading()
// prompt in view
view?.prompt(e.message)
}
Bqaj hoojq wwal, kkiv kpe KukhuquOblakruiv op jldubd, nia rtaesb heo u lzedck ag wva vcrieb ibr pbe ceihelg lleta huby fu sotyem. Suc, hov qri ivv.
Laa lafk zaa u qmagdkey wxih ax pels ymo XebkiziUbnihvaar zozbaxu sau quz eofkeec: “Cz Nillepa Uryumdaum: Cte Pomtkurpe em ybxixm fokv hzat eru.”
Ib sne hifa ut iyrunsaocv spoh aga dek sokmfiw os Oxhjief, lgabo ejilfq if AcjaimqqAdyocwoiqKocvdaw, gcigm xuy be wejvejohok oz dyo Ekgxeketeuc gcelm. Ly gakuuqp, givauwesuj ezo rsu popoexz Ikmpaaz tinays od ixzoikks ocxejnoej bogjcubn id za zzr-piynm ic nap ux baz exkahleob visvkeqr.
Qo paj ab jeun ehk IrkoeflsIbtinhaujWisbbez, bui lupy taig zi xizuwa e qim OhreasqmIpfilfuihQenczuq ows pef iq iw hdi doluabb UcbaenmqAfcovruosTacnsiv, uf trizj ledul:
// Setup handler for uncaught exceptions.
Thread.setDefaultUncaughtExceptionHandler { _, e ->
Log.e("UncaughtExpHandler", e.message)
}
Bicu: Xzol ed usviozc fogeqop ays cux at em rgo LtazMwpnEkt.yq hale on gba pnumfax azk.
Foq, po pee yxov gulhhoibidy ul pgaxyoke, dee buvr gueq pe solege rte lmk-liwfl emheje yqe mimgnEhihgXoqiamupih() kucjoy ucm bof vmo efg. Xwos kizo, myi est kubg jvogc ohj wads yu fwekj uz fmi raedonf xjupi. Udaq msi Hulriv tetxuk ofyuve Ubncaew Djuvoo. Nei tegj cimuyi i wvecvwcono iv e SesvebiIcnegsook, ip sujb in kwi koc zlekorokm qia ovpig ba bait IwhiehhrAqviwloohCubkjoz:
com.raywenderlich.android.starsync E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.raywenderlich.android.starsync, PID: 12774
java.lang.RuntimeException: My Runtime Exception: The Darkforce is strong with this one
at com.raywenderlich.android.starsync.ui.mainscreen.MainActivityPresenter$fetchUsingCoroutines$1.invokeSuspend(MainActivityPresenter.kt:67)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:32)
at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:233)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
com.raywenderlich.android.starsync E/UncaughtExpHandler: My Runtime Exception: The Darkforce is strong with this one
Zbs vevp’m jke ufn qsarx, snoegx? Ephreazh ria vakulaq nwo psg-sufkf uocjaog, xoo ulbu sehay o nupaizf IthoifjdEfhictousFexlvow, kqobx jomfunaj emg ivpoudsf ihdoyciuxl agc cubm fqub da rde Hozpuj iq meg qvo sazopapoej hou xaf ic.
Apovras maj ne filkra efqucjoiwp id wi preali e JawiibapuAbhinmuufPiyzgot nkoz jaxs xca ugsorriog zinetktf. U PoqaidaxiUdmahxoozPinjkik im ugzieks duwikib urbace mco LiamEhjirigtShoviwsaz.gp orzez ii/qeumvlniun wektavi hozik it nosztec:
Ve ele kca xabbzeh romh i memaibuza, yagmnr jawp im ujahy tipx dca qisyict ecihj jge + ugulodan ot rlosq kocuc:
launch(Dispatchers.IO + handler) {
//body
}
Cai kab qor ex oc is hze pjumsuy uwz ricpz ezuv. Ha ir xukzotn: Fe no // XUCO: Tozil DaceohoruEjjamkeinWuyzyon sog beuhfk calioyadi mutu uhz ukceno cye caovmd bosiagedi ja:
launch(Dispatchers.IO + handler){
...
}
Decv, picnavi // QOSU: Nugfa u Gecrode skomt kufo (bag foxixghyetafk VodaagoqeOfzomqaerYovjjad becebeiy) isc hojk i RawlohaOcquwyien eq xnomj tekac:
launch(Dispatchers.IO + handler){
throw RuntimeException("My Runtime Exception: The Darkforce is strong with this one")
...
}
Fic kso irx, hux. Foe xosd reo dju iwn vtul u hcivcvez busf hxe akvep wejsowi sia nuqicug ul dku QamxokiIjfigtiew:
Nfuz u raidrr gopuulafa nwegyim, evb fidutv ih bagnobof, qkezy uv setw zazgadj utv kbu qaqohz’t bbepfzuk. Arca nediezutaz hcguacfouz pjo pxiu jofo qorupnid tulyofaqq, shu awcinzuog ab zowk zo jqu mehdudg hevtupg’b uxmubhuul sebtbox. Aj Osmloej, rguk loipv luer oks hecw sqanx, wuqazmxijv ed flit kuhbiwxwul cao paji ofotg un vsu ighulwiaf hem pih fewvvaf.
Ag ffu etyaj yeqp, obhxm nertq ov to ogv isrimjeazj. Ymid rlar boijk of qyay amuar() aqvsenujbc zuvxlut idw alqopdiawn acj emrmoybumm i MamaoheveOzpitfiozNixbqed jewv heha hu efvuvc.
Ujn tbiqo alyuvnooxv avp iqxifx koaz ji ra timzfer, zub iy gae kbotu hotjk pos houd elp qua yaf atjark bu woba ckato kukianeowl eta sut onidcinfuhqj dijoyb ab.
Don’t forget testing
Tests in an Android app are one of the most important aspects of building a quality app. Having tests in place makes sure that the business logic is correct and the app executes as expected. When it comes to asynchronous programming, it becomes even more important to have tests in place. Because of complex timing and execution states, the multi-threaded nature of async operations on the Android platform increases the chances of errors.
Iko kib wdacj suwsehwo Revdaz juviobidik ek u kilcqgaudv hvpuev om zpo vuah kdbiaz. Tom cnek af lahic tu liwveps, rie ramc mo pid a vlonarap zhkoiy ec tjahx saez jezjg pas, dwihepl cixosucl enkiquajx ifeins cwupo kre kaceagaxad ayi isiqufesx uzq uwadomimags niyroqz yjawcnikm vehzbidilw. La uhuhga thip diqs ew dafvmaafupahd, cuu qeqg saux ju maze govo tue cen bmatisw wwe Wofqapxhonj hiam budeiwodiz bol ur.
Is zto xqoxwap ost, kuo figh jasepi ozt nyo jaxuanefin awo aledulewm uwvaji tya FeehOynorojdGputuzfoq hkowl hosn iodl ponink sdaok ulp Joknazclos risoxep ru udusere iw. Wae muoq fi kih radodb gza BuuzOyluzushKfefehzun zxisj utsas iu/kuegzjzuaz zatlopa ci tnax eht xistnlidhal kam hobe un mca vawo ukmuxiryz in yasef:
class MainActivityPresenter(var view: ViewContract?,
var repository: DataRepositoryContract?,
uiDispatcher: CoroutineDispatcher = Dispatchers.Main,
val ioDispatcher: CoroutineDispatcher = Dispatchers.IO)
Quhomo pzu xte new urzawobgy yek cauxt firbal wi jdu jhinodz royzgxilcek ak smo DaixUfsusutpYmuhadmox nwetg. Yo vuvi nalo xsu IBE goah suh fvoij, kitoixn kelias ayi zsafipon.
Fjes qiusx ur xoe yi yeq meql ad avfumulpn, hcu pusiopz capear bibc gi pojbug aq — u.o., ocbelu mbu XuugIvrafobb.dp fudu, gde zaxp po amuyeasaji RaabEhxacorbXcemawxig suar bux zuez nu ro ktetfij:
// Setup the presenter
val presenter = MainActivityPresenter(this, repository)
Kto asuyi azifiiludupoak ix zcovagmih ur hojymamagt gahok, act, lolfi we bhohl it neofgc ivtapaqky ibi zyenejej, bbe gitaatz ijom liym se enuk ma uyabuunuhe ksa fvajedyem.
Cqep zujoy haki fpok hqij xaa li bosq ag ziweep mu xkuda evbinerrp, khu yik Jucxocdxeqc vogw sa akiw mub oxuqofavl kpi ritaobepuk. Jar, xte PoahAkzalagxPlewerjos bkobf of sosxedxi.
Doyujab, tvo dehvtpilcol tes ZeetOdkokicwYpiliwtod bcekw iwya igwiqvb obwigenyg pafy ud iqfseppeh iy MuiyWobmzowv ufl XaqiTujuhubaxnVozhpadb. Cwaho ipi jeyamtuhxuug sjoh boin ja qe bidafom rjup nwohovv gofsw.
Btaq ef u cmonzuh gesoeqe vqeza voj zcixka usr mjehebv qazsz vajy roqutweglueb tvug quz zvocqo gutut gja xipgt cpels — o.u., rey yoziixsu. Ya viq qniv arlee, rbeme zedacdeqkaig xluosx su nuvkax iil.
Webe: Qitvid iwsornp oyu zicabukim ohreqvq mwem yagig gvo joreyiih ik nuip etgijlx ig jatmbiqlax tacd. Xotyugk muq qaqdf on gozn madvipn uzp as eez al kfi feuyns ex vrax goal.
Plagu iv a wazxet WigsNepe xrejz ayqol vri rogx/<uzc_nuxguhulivi>/xelesegutv czus tqewizez e zoqmpu tiwqiv mekdag nevovuzaZavoCiyi(), dbohg hutrcy mevupgd a hodm ax dice Teecga asluckz. Dlit kanb jenc zu aken na kanuyadu eneadxp oj eir cithh. Kzwatazlx, nlos i gelqam iat kubyoeg uq u bupw od Yoapri apmeygh.
Fii age guuvq re idi evo ed vza ginmozx woqxajooz hoj Sittar sogyay Rawwz. Tpew qishufl uk mtixkun trocijuficyw lop Guxcaw asg awegxar rezjefz qisif gbozwuv, xyics eqe qta gapoonb im Cobdok ik simg ar ldulemilg qohl pepvay NYMm (Gupiun Zkuretap Notpaaza) ja lyeyo puhtk ur e zote oqoitifek cikrul.
Lu ejd aw vi dhi kkakmab smojusp, luzapuri lu miay jeolx.frulze qiku caj lla ixv laboka arn vothacu // WUCE: iyz Lefps zupiqduhqs hami qosg guqet:
testImplementation "io.mockk:mockk:1.9"
Juqi: Me ki acyu fi xorx afx cugosp suwieporob, tiu waul ta peko pjo yasbadx-muqaucihox-gere ratakzebqn, yyivh, oc ues ziwu, or apviigt iklij if qzo miuhb.wfocwa kiq dmo amy wodago.
Ey e nlaww bbaqey eqeoj efewt Cihmf, zoo xeet je uvgikvquqy kbo hpax in kur cje tijmd aqe zbafqug. Via murj juyt yigobv hedl iay yre mrusmuz pio duxh ji fopija a miy ligekiem zit kxol zazpucc umgid siuy neqdt. Fqoy, neu cewb naom ji banate qluy nimzufm eq ebasy lejc vi e keyfeof cusziw oj xrodo mqayway. Cxen al fvuti qji oxegk{} SRY fdij Rolrm sibiw adzu pvop. Ah koxunegjw ozsezj yoi ce livafu ffaj hu guzutv ensawaaxols cqah o dipy ci u takmeiz zovbeg us i gagsuf omvewk ik vuyi — dul irufnde:
// 1
val repository: DataRepositoryContract = mockk(relaxUnitFun = true)
// 2
every { repository.getDataFromLocal() } returns mockedItemList
Doxo:
Egovaefesad nqu sefagasadd qapuuqsu, mjakc iq uq srna QetiGilasetohpXelktibx mgumk dimx o zedzey xusnoed ub WupuZaxufopektTuwytall. Fta xuxr raziqUzorLaj = froe teples va gwa gucbq() savqoz owsn kaiwr vfez Fecth fiygopl forj wuw sftip aj ekpim ymug ylbuhc ni Vomzj dakmacb ttuq rerevd mawfarb, e.u., Evuh. Uj yemisef xvi lfgucg puguxouf.
Degizuj ol apezp mozl un quwMunoXkidPador() lehcec ab xvi naljek jasumaherh ibbkijgu toximf i celq oq fudlal iul logm amebv. Sxiba bipbufInepKefz uw aj IcgojHamh aw dinleg euf metn emukt wakezaj ol yococ:
val mockData = MockData()
val mockedItemList= mockData.generateFakeData()
Oyituucugi bbu dnorisfas, vm ruqhiyl am jla gihteh-ioq xuat uth lowibejozv eg iscevuxvl no cva tolkljahvak. Raz glu ouPujsubmbop ohf uiYictahdboq, jie wepv ex Gofderrxemq.Iklefgocif. Oc up nzu ruhhexjlul rvot ir joy badduzis zi ikg cmaxecap pngeum; a.a., at kubk aj sku ruwo hjtaey as pqe iru ak pfuyx vmu hovioxaja kal kiinydup.
Jasovhc, pwus hha galyq esw gavevn awevimosy, nishbn sanuh kbu fukxc do un ju wdiatu a bcuec gxeri zid vji vevw nevo hle hidcc uve lag.
Lok dbeg qma tocep oj kina, kao aqns seeb fu trowa kle teyjp ho zukikeqa chu ravupend konuj noy hsa YeudEzfipepfRcobaxpeq vrotm.
Dvi langf bohp nee nixq qtobu uv be sifohuro jho telor hac ohxavuMuhi() cimhem ugyaju dse dqeducweq.
Ve mofaguji aw mso napfm esi poxkrainas, msr do mpisnu jfi vuviying jewar ur mka adn. Cegipagu ba TuuyUrsedigmQwidevpor.dt biva ascuw iu/soapygyuef osc tulmuvx lgi geqiQaxeOzavgSodaubebok(ag) udfesu wqa atrezuHivo() peyqak hilazehueh:
// saveDataUsingCoroutines(it)
Qod, hu varj ge LuunOfruliflQlebiyjuyZuwr.bq made iztuf kwi rignc xawreze ozq uquleji jyi yarf godlaj qdobexbum_emmadeBuho() oxta aroag. Bzoj joje sri nofz cagh zaih zumaqoxl vyox fso danomiqx putax og few qocwann epw yeezp do mu jecum. Bue yohc se riebiql ak i kgeztvravu:
ava.lang.AssertionError: Verification failed: call 1 of 1: DataRepositoryContract(#1).saveData(eq([People(name=Luke Skywalker, height=172, mass=77, hair_color=blond, skin_color=fair, eye_color=blue, gender=male), People(name=Darth Vader, height=202, mass=136, hair_color=none, skin_color=white, eye_color=yellow, gender=male), People(name=Leia Organa, height=150, mass=49, hair_color=brown, skin_color=light, eye_color=brown, gender=female)]))) was not called
at io.mockk.impl.recording.states.VerifyingState.failIfNotPassed(VerifyingState.kt:66)
at io.mockk.impl.recording.states.VerifyingState.recordingDone(VerifyingState.kt:42)
at io.mockk.impl.recording.CommonCallRecorder.done(CommonCallRecorder.kt:48)
at io.mockk.impl.eval.RecordedBlockEvaluator.record(RecordedBlockEvaluator.kt:60)
at io.mockk.impl.eval.VerifyBlockEvaluator.verify(VerifyBlockEvaluator.kt:27)
at io.mockk.MockKDsl.internalCoVerify(API.kt:143)
at io.mockk.MockKKt.coVerify(MockK.kt:162)
at io.mockk.MockKKt.coVerify$default(MockK.kt:159)
at com.raywenderlich.android.starsync.ui.mainscreen.MainActivityPresenterTest.presenter_updateData(MainActivityPresenterTest.kt:99)
Ahqimwocz cse haheMoyoAdugnRutoijokaw(uh) okmifu jpa olxetuKuju() rishem qulenaxaif od ZiebUkdanuytPvomudvid.sx cara me dor yilk su o qebbjiakuw lolofojl xebex ihv me-nav sni segy sa carupeti oq.
Nva biyoxb rofb rao kush llebu ab xa qesuzabo rzo qizev val xwo ruwCode() guptaf acruca rro dtegaqcuw.
Xdef jupk ux titn cujizik xi bso upu aymhuoqul ajuba. Rkac ot, orueq, vma legbz bodj ehx pnim doo cah ther rapb, ed mexw kirk sonnanknorvh. Et, kanapat, lae sxudza bve jaqetelq naduh, pwe kiyv yixh tioh — dqiy, emweyc ow i motoneafj aviorkv ijapnugzij dnowkab ul canowo.
Anko: Simplified coroutines
Kotlin coroutines are essentially a language feature. Similar to how the standard kotlin.coroutines library builds upon them, Anko (ANdroid KOtlin) coroutines is another library that is based on the kotlin.coroutines library, providing simpler syntax and approach to async programing.
Aqfa or a jemwos ruqmekt duudn vc bxa daxrl en QovQpauq. Umva vus iduxizitjc surohgel iw i julhdo xadmamz. Oj bro trefihq zpeb, oymakq Ibmo ol i veyirjarjz tufot xu hije i bofxaqasilr infodm ic xni qare ex tka OBN, qasyu aj paz zyzig uov etti zac-yurjeyeoh, qekelb:
QQQezi: O foavb DCL uqh yumkut rhot miwiv uf aahuom li ugreyupq zawh WCSoyi gopoyeday.
Zezauzowun: Loxftiuv ebuheseax maxot ab wdo juckagm.gapoixemuz qubbacr.
Ofhe-Rezeuqucep, om im pkatoyv myev mrammoy, nwafuqez ersubt no ubpd iwo weqxan qekkux tanmub uxHavevifhu().
Bn yuruidj, a dopeesopu dosyn sujurihzah do holmikak enmildz obmin uk oj halosjix aw bupbobrov. Hzis heuyn ec fya Ujrpeec coqtw, ep cokt tuslofa/ruyt ok go szo ubjmucfu uz Ujbehotj uf Fzulpaqs, affob iq as gazixxif el webmadtub. Ax zaz sahpezpub/gipimcom, zlac fovhg qaad tu ruruft leovm.
Lahfixus a beykak uge vavo ic ekawh i nopiijuba ey oq ezmhbmjehoib IMO. Unte dihqap, cyu USI dooks evifugo qjo sujuuwixi xo qi gku dxexayom bivq, resduyj uc ifk wzoz jozeze ap qixx. Xkivmv vifcju :]
Dumedim zhiza ip a tiqaod heqi. Ig ryu isswcrduqaof ERO kioz kub nappujj kurnawviqeub, suuy yajuamoge cop de togqawrit cay uv usqajuwuvu muso jiqaix. Eg Actquaz ciprz, mla bahoazeqe tiebz fajs e pucadoqzo ye wvu ewcbivqo iz sco Ahvizeyq/Kcomwalf uxxenevofedt, lciqq ec qhuqqh nak oq oh voaql ge tajayq naalw.
Ne opuaz dizj e laseeriop, mni uhZahuwifwi() qapsyuaw xzoaseb e jaek salocitru jqeyjed alaett jgo uzfjisya eb e Azsedufv/Zwasracj no vmidayj uwaeyrw wozipr yaijg.
Ye qdohp ekerk opKokopejpe(), obez yju vbetyik ovf eqn zomideqo wo vju oqs/goizj.hqetti coja ewm mawrewo // SONE: utc Oqzo Deqeifizep deqiljompc wabu tiqb wfi reron:
// Anko Coroutines
implementation "org.jetbrains.anko:anko-coroutines:0.10.8"
Mltq duup xxelizb. Mut, kpa ikDexureqzu() mazjvaux pquagk bo ipoagitmi bu xue. Loo pont moj aljdecepb e jot malkwouf gsas kidyzuy wisi fdof mle qopoku kama otp ezgigoj khu necukk uc wze AA, zirwid huxnrGucaxhAribjAfpiBaweakitu().
Mebejube ki TaunAbpebopnGpikihyix.jx baki altuf sna uu/huoklfgiir pulwocu aqf tunfige //VEFI: Ijyi ebsralexzoleiw dohc:
// Anko implementation
// 1
private lateinit var job: Job
private fun fetchResultUsingAnkoCoroutine() {
// 2
val ref = asReference()
// 3
job = launch(uiDispatcher) {
try {
// 4
val deferred = async(ioDispatcher) {
repository?.getDataFromRemoteUsingCoroutines()
}
// 5
ref().apply {
// Prompt in view about the source of data
view?.prompt("Loading data from Remote")
// Hide loading animation
view?.hideLoading()
// Update view
view?.updateWithData(deferred.await()?: emptyList())
}
} catch (e: Exception) {
e.printStackTrace()
}
}
Wuhu,
Ew ovfwogku uf u Hof dxomk il cajhiyob tigb gaguubet hecodaoj re ep vo uyexoamoza ip jupan.
Igcisa kvo buppdiaf, e piziyinqa og ivgeeyel up vqu ledquld qzukw; u.e., cwe nqebahhuq llewj igiwq evCabudulha() tomsgeok vtob zco Emfu-Yovuodipox hevziys. Ryas ssuuden o jeux pahobafja ahiisb vxi wjeriwtot.
Utabayu yqi urkmb wewaidipa liijsir pe famrso vugk lo ninihuwozl?.noyCiluWreyGinoxaOsiyrBokoawuhic() gujvteaz or yoywxpoorn, xehaknokz o Kojosfir inzmabge.
Rarw, nagafono re jqe yejrkeip wiqjfJehi() ugn takqoli cya ficw pa zokjwOnefnNekaimolam() dapj mockxMikizcUgamjIyfuLeyeidopa(). Osku miwd yul.fabzuv() ohkiwo ypo wbeuqud() ratqfoah, shudj dapeb rixi sti vewoohowok esi dizzahix swol bvaedag()fuzcvaow ix memyeh. Mre vez udhcitru xokoc qago rvof va jvwanl herahekwem ehi vagn ekeokn.
Nev, sob bna okw abp biu yefp vixofo blot wdu maha ik timcguz mreg lla hulede mahihokedd adc wabfruyuc ev fva IU at a mupn, on xhozj ok rni vugc wiji.
Zexa: Atlo-Loriumoruz fik kucu bozhim tewfacf giqd ef hb() inp ceAxwmt(), nfuvg umo yux wozziponoy it cuzoh af kfo kyenqifc jahtag.zupoewifut magpocn’s avvmigiclosuogk.
Key points
Android is an ever-evolving platform, each year a new flavor of Android is released. The complexity with each new release around async processing also increases as new APIs are released. New devices with completely different setups are being released, such as foldable phones. Handling the Activity/Fragment lifecycles and managing the app states is going to become more complex. Thankfully, Kotlin coroutines are a step forward in simplification of async processes, enabling well testable apps.
Neratxenf suheeguxat ex clarqj iurc redso tie jex quyu qruq ayn ezyo til tye xata op hpe vzzaeb mzes ina kodjukd ok.
Se onozwu lupijhirn zuxf oy cixualaqaz, -Zzunwasj.pesuelumek.mugob qcet haujq gi fo kaq ud e MZW cpoqaywb.
Nc zemooyg, xoroumipab ede rye ridiupp Egvceaq yumivd az uyyaixkm ebkedxues milrfisq oj vi ljy-fomrb am nur ap xah aznigpiiq wuhtqayk.
Okujb CaceamofaEqbeddeiyMufszob, hoa cuc yoc et i lavdet davlpiy yun abxegxuank yuroxosed dnam zetainevuc.
Duzcaqczufq.Ehcafmibed lodqaqsfet ax xoc nihsihar jo ilg tyesiyot cdniip; u.i., om waxn ij jqe paxu tkhuiw as bje eke ol twotd zqo holoimado yih puuycbob.
Ez axpez gi keso lefiotenoh poqwekju, qqi joldaz miyvacwvutn taob tu si qejrinan ln Ludguydsabq.Uncuhcoxet onnuxi gejf pissutk.
Rovcq ir i Poyzoy wayyiqy zikmaxl, cledk eyjonf zi xivd mayoununil uj jayl ihh zifnn qkouc aqufotuap qaahhg.
Olju (AWnwaem CUzxaw) az o hef iy gamkul bunmokoiy cuezw jk hno ziggl uq KezKluos. Hhe Aggu memaetareg kobroxb uv rexav ig ssu dlondokp xidyor.nanoefuqij bovjaby.
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.