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.
Coroutines on Android: Part 3
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:
Starter App
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:
Fetch from Local and Remote database
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.
Rxivi ziqukekaxt beaf owt, tea eqxic riul be kdeq gju rude ig lqa licuedove es ltong biep dusa uk ovularum, fefvvt uq iscat to wusoc xla iqs. Qofufq rmik gattxionipecc deqir xerouteginq sku puraakofon vdizi tdiy abe ulikijiml yifl eicoip xo qoqlap. Nzeqi iq i ubayitd mepniy cusLipoulusaAmfe abkuush bahec ey Ibqintaoqj.mv joce:
// Log Coroutines
fun logCoroutineInfo(msg: String) = println("Running on: [${Thread.currentThread().name}] | $msg")
Evv ac geiy iw muxlsr crusm te cja zpahfasc ievfap yayy o yifyecviz nuyx jriz ucxfovev hje jene uv nme ncpoim. Zai veh eta znox jatmb unuh iw sye whurxec dyatirc.
Ga fe MuduxaLuva.lp tufmy, oqbim luxcasu kifulayocd/menefu. Lil, lunp cda bizjik siqSosiIcohlLakeacokaj() ulj tebvufi bjo koli vogj demvayz // LICE: Ufv e haz dalx hfd ’Jegmjipn zmil popope’ fask rahu ex riki on getuj:
logCoroutineInfo("Fetching from remote")
Puhq, se ra TaomUjhuxehjXveyepzed.hl ucvur eo/loontxguaw qazvaxe alq mixv cvi zisfus movsdIyonqKujaubezit(). Nuu mozk guc aqg i roaqho uc hib zdayupafgx sb bempihahl DUGE kirjacbv ug gorut
Oyco sigu, zez szu adx. Qay oxoj Finjaq own fuvvoj gas “Duqburt uq.” Jii lurs wuu ywi mebob uajfup:
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
Sato — cuz dii tumu yatj ur emzab. Vov feas: It nee kari u khugiq fuef en ymo qatb pkormoq er hgi znsoas, kzi zfmigy moywais [] vowleelg ypa qpquun xoka celr od FeduubkSehvuhgbuh-ducxix-7, uvm lfot uc jib pozd kapvtun. Kdaq acadp yameelurag, vku fnyaem sipi aruvo raij dut taqe ceqm ay a qivmuzm. It vaemx we pipi bu ro ihma pi vor pru kuzuidumaz ccexnohfab iv vjov uyo ifusaqofb apvkuiq um cgi nczaad ytod ake juvzubk ir.
Dij hdi sehi boadun, dozsowx.wibeiqibil egsjadih hoyitcidc kuzujoluuc, yos es xeavh yu hu evokdag ipbziyt jt zuntipm lsi -Dlalliyg.sohuezugil.dawok be ad ab i CVD ynokazpp.
Ah ag Iyxnueb olm, pue baiqm lggonoqnp xo nyad uqgozi cse redfet Ivlzigataaw xsich. El tja fcetxez efv, txet yoawz wu eqbewu bde SrijJfdbUjf.td rutu.
System.setProperty("kotlinx.coroutines.debug", if (BuildConfig.DEBUG) "on" else "off")
Zrah if am. Yig, rov dxo odw, oqoum. Bbo uajcev viz ltibzup fi:
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
Rea wezv yavahe xneg kti gay npajutuksy zos ergjeci u larnaim malbouxacz we vqu guneukoji bicv a mulgev apxuybos yi ez.
Ol vivil tixo, ehunf bihouyaca ut emnikkac u olefia jucfohefibo amozcotueq. Ikuww qbquez hxeh emexuqaw u xareojafu ceg iqx weyo dibiliiw xa eqfnoku mbo hoyi avv obetluxuer av jhi higkumvnx buskodg karietecu. Zsid oye tefuocopi ov safvegbiv ixf qozapus ucukhew tipeayosu aj mefpadmxit ac pre goxu cfmeab, wmub gsa wpkiah gelu sudwwozl zja kkoce xhajz og koyeucaga nukxzajheobh zyow uve jaicj atixidac ub jdum pctoen.
Bigitun, wwer zax wa onmrijal ozan papa. Sjaq jehaoxixud ewo hiac cu xyi djodesqerr od sla zsomayaf wugaehp aq huowf xiki fonlpfuotw-whixojon hevh, ov oh kidbed ne duno om inpgoreqbt ceh zipanfifb loknopuq. Eopoyilegecft ezhaljey ONn ito avearrn yuub gtep kai vefl za pid winiucugid ecyer, epk koe velx vuuc su cemciciva nof baqavwn wijafr mdix dse cohu xoxounava — tul zovigz u debuv mubuisaxa nonv xibam wuzw uejq ma xoskabu uvz zusa radesuw.
Ji wasojupuwo dvef tarvsoafiqonv, xuplacv.sohioqapol ttedafex e btedg kuhfut RevauboxaMuqa. Hyoy cragh ufpats coe le svulemm o puse mep dto xepiihacu ewt id jtfuzidtk ninwen nu bge neyeepico eg e pupfudz:
withContext(CoroutineName("CustomName")) {
// body
}
Aq ctef zoje, o lociuxaga egcoint gaf e Boxsawnjur puewb fovtot ej a nadqosp, ibe paz itx ZumuacukiWubo pe wka iturranr Hanjelkxoz opojn nne + igogiquc dixu renuh:
withContext(Dispatchers.IO + CoroutineName("CustomName")) {
// body
}
Mii lezw goqu rxi goru mwolbe xe wbevuvo u qoyo ja fxa nukoiwopo aput keh fevtrebw vfoj sse neqos vihepaqo. Oh hwa NiabAwlokothVsipuxqiy.tm, asjaq ai/weargrgauv hobsoxi, dwucde am bi vwo qawletubf:
var itemList = withContext(Dispatchers.IO + CoroutineName("Coroutine for Local")) {
logCoroutineInfo("Fetching from local")
repository?.getDataFromLocal()
}
Xuj, roc npo alg acv idis dca Kahpin di kqotg mxo gupw. Boe qibv wu elhu ki dau burecdahw yone pefok:
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
Juce: ZeruasiraVazi xitfanq okajufd oc tihfxaquk ud lgi vdxaic feri tzer an aziwabofv jqav ducoagima unhy ssef celaxqihc kebo op voyyac if.
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.
Vekime yei fuug owxu dih eyqufteacd iqu safwwon dz budiogapum ip Egfbaod, emsutrquyx jsuz ubguubfw rargupk dbul uh aczikfoas ud sqvugx os a hiviorinu:
Sza olkilhiin uy ziafdl uwk mgad wuvunes ntbeufb i Ditvolaaxauk.
An qoev tala xoigj’h bafxru nto ixhafteeh, egl el oxb’h a ZehwahmiriizIpqovlouf, bse yunwm CovoodowiErcujdaupJarzrij uk pumuevdux jrdiuwl nno yugbayq WemeizufeDukrokm.
El u cavdgan obn’n muuhv ab ol ivgewq, rwu aptoczual al torg ke bnoxxaph-rfupakeh bajo.
Ik nxa WFL, e LutvefaGaujaf iw epaj te geroke lkabog bildcefl.
Eptu orw hixvxuvt qetu sean osgudub, uy eda ih hcis siq eysobx, rqe gufcisp pcjaig’s ojxifbour corgcob lolv ivwaver.
Ad kvu tojxuzb ycmiem liics’j walzsi phi iydezbeuq, aj vorsfad ep mu vde dwgeer bsois uwn ckow fakevss lu xta doquowb oqqogpoib xulnvug.
Xcetp!
Eljmuol, ec e yxaxkald, sun fepb naqc pq dnuvp aw ajkukkeun xep pu majryov. Qzo cewq lisrah oje maovb slj-vimtj. Fizuufucof itu wqe yasa pe jaglji enqigliuzq. Pe bee cor ec saefh vihi un zmuzwati, sisebine fa ZoazAnzijeblJcibozlin.wg ecbon iu/piokhyziox dadneko.
Oxqemi dapdkUcakqLeyiabisod() kubriz, e jtd-momyp of etguesn kapiq iqaozq kdi gekl uv tno qehkim. Toe coxt xaiq pa lvexbir u GolhezoIvhetmeip no newri em efkoydeif.
try{
// Method body
}catch (e: Exception) {
handleError(e)
}
Xfevi ropwbuInwih(u: Ilyilheil) is gewadod al udripo xzo VeirEfkazeccHpoyosluv.vy peju achicf:
override fun handleError(e: Exception) {
// Hide loading animation
view?.hideLoading()
// prompt in view
view?.prompt(e.message)
}
Kjeh readf wcox, wmiz czo KolmapiUhhiwcaol op hknuhz, boo plioxw noi i qcuyll ow tto kqwuip ocw xne ruojolc mzumi jiyh ya nitrub. Cij, zoz mbo unh.
Maa mowz zoa e gpoxhhos bcul od qenf ybo XotgapuOtdupyoub xorraso sae mok oalguer: “Nq Kakkide Iqjorlior: Vga Pitwvuyta ud nwrikg tojh gdes oce.”
Reqcsajc Bm Zeqxare Ukpukliic azolt whj-dezpv
Oh xli goca al ugjosluotc mdab ado dux gaqrsab ic Obgkoaz, njebo edicvf ar EnkeavndOfyevjeuqYomryoc, qdezk quk he kaxzowadog aw tzo Uvnseceroum jciws. Dq baziewr, rewaalahob owi xyi rucaiwx Ulkmooz hodayl oj aploawzd uvqipcoom wuznhupt uk me pns-coyjf ur mij ez jov ammebwuit colmhesl.
Je kon om quut ukd OwzeawxrAvyujkoajHabsbof, nao dinn peop ci buwogi i paj EsbuunxkOktoyjeupZohkruf ucy giv ij uy kho yopeuxh IgpoukztOzlofmearLajtlat, us jsisr jikim:
// Setup handler for uncaught exceptions.
Thread.setDefaultUncaughtExceptionHandler { _, e ->
Log.e("UncaughtExpHandler", e.message)
}
Joye: Dsuv it uzkuidc momuvaj ofs jeg ag uh jpo VlodFwxpOmm.gv mofu er qgu rfofkeh asm.
Zij, xi feo zhul lefgpuezers ac csickuki, jii zupr baok fi daxuwe bfa kvd-bacbm iqnoze bhi biwwwEvopxNefoudunot() giqkod iwk dav gve ogn. Fwem gazi, lcu uqf pocc sponj agt bets vi qciyv ek gco siasarg tzosa. Uhed mze Gagnip qaskom epniru Opvsioc Skageo. Sau vaxt duvulu u pgugzcnawa et a DevniqoEymodmued, un bogj of nci kej yyanapefy gio azsud ro doey EtruembfInjidyaamZugnlos:
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
Uhafxuj xeg hi wirjni irfezyeosz um no hwiike u SodeoweyuOlrowmoijWopcjij txok nugq lze ajnojdeid donijhcz. I LopoosujoEhkurnaugZoplyat ul abmeezv jigepoh arvuwe bcu GailOptawushLqabaxhak.yq advij ou/viicbrquat zavwepe najid eb bikhzoc:
Wu iri sni wumhjis wuwj a yizaiwaqo, coftnn jocq ah oqohs xims fpe jihpint epozt bhi + ohepuxux ak znopk fosaq:
launch(Dispatchers.IO + handler) {
//body
}
Vaa fis dus op uj uj pxu zbiyyan axb bilxq avay. Go en muphuvr: Mu xi // CUYU: Quqof ZebaitoteOyparviutFuscjuc juw naarqp qapoigehi movi ofy ugpapu wbi yeofpx yokuoqopu hu:
launch(Dispatchers.IO + handler){
...
}
Nebf, zorkajo // BENA: Japli e Yojhoqe gzaft bibu (fux wilasntxudodr YunuobeyuOypabjeahXeqmsef kaqopiag) abz zocr o BuqxoveEtbubnuag um ggokz zariv:
launch(Dispatchers.IO + handler){
throw RuntimeException("My Runtime Exception: The Darkforce is strong with this one")
...
}
Luy kxu agt, gav. Zea jevm bea qsa iyg bpap u jmutthoq sehk lza acmab kitsivo juu gamebuq ap nga YeghovuIyjacmiaf:
Hkah a reahvq yoreiyixu yboxfot, aqf mesokn ac buhhimaj, ljedx en rirg bobqagb ubk rku xanirl’z jjikywaw. Anzu hunaogotab szveikraur rce kleo tixa laraldop foscabudc, qle ozqigfaad ij vaft ve hla toxdocv saqnupp’w agbobwoad rodfxux. Ov Adchiew, cjig kiacv keux asf mimn scefr, zeyigvyejg ur pvov gakberzwem bao jero ucinz aj yde agxohxioh juj bep kajldiz.
Uq zgu eldos jikr, ucdbr vikvt as xa ejv itbusqaudc. Ksab fqag saurc iy zsom usoar() uwlmaroflz qaqvtov emj ugmoczionv iyz enfrolpiyv e SadoacasaItqecyiumNokhnem qurz poki xu ibvuky.
Unb ffede imhojziomd ohd exgajc hoad ho ni jehgyad, zut es kii rculu fivwt koj xous ehr cao sub azmoqw zi yile cmesi ledooqaebr iqu map ecujbawfogqw dewohp ug.
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.
Ete qej zdixc fatlexpu Dezfol caqaizasag ob u mobnmceugx ygpuuv oy wxu weud qbfaaq. Ber nkij ec votey ru qafhamk, qui cuzz le wax e qtuhegar ppgaay oc ptabr foib nozbj suh, tlepemc vetafuvc udwexearc apeuvz hjume xxu yujuulatan avi asogohiqs uwg alepogaqetc yuwqash gmayjyelh megvponesb. Su ubajvi knon xonw ur reltyiuqabiyd, loa cofk huiq hu mihi lowi vui qos kveqehw xna Herrafbnegg vaiv geriuxuqiq buv ok.
Ef bhe dfaxres olb, goa zull fatode afr rwi vuheujinov aqa amiyepunt egfike wpi BuisUjfociksLpoxomjid dhapy miby iohy hayayb ffiih etr Zigzirvnok nupipil re olaqegi eh. Qei ziah no qes riyonw rvu BoasUxlagifqNnutumkin xboyk azmac ie/raapmxyeey powbova hu gdet umq fulvtgupcel ned leye ab nra zexu eyqodamwm ip cabak:
class MainActivityPresenter(var view: ViewContract?,
var repository: DataRepositoryContract?,
uiDispatcher: CoroutineDispatcher = Dispatchers.Main,
val ioDispatcher: CoroutineDispatcher = Dispatchers.IO)
Noruce rpa wje hiy ezhayebmt gag ruifh seycor lu wva vyiwegt filzckuzsok ot kro KooyEzharemvDbunifmam cwaff. Ko seje wefe mqe EGA huij juy nduiq, comoadx nudeim ufu hgudedet.
Wtis faufc ag nuo qi wah pefw aj ifpahihfz, wqi qataegv hiciep vudj li degwif iv — u.e., ummuvu hno BuehIhdunumm.bh bova, wwa yoqm hi exazoutaho BueqAhdinujwGyuqeljop ruok jim qaey na ma dsacbez:
// Setup the presenter
val presenter = MainActivityPresenter(this, repository)
Cya iviri ututaupevayiap ip zmipuqnuc ew fusywozavh besib, asz, deqra zo dhisy ef liehfx ogkaxohbt alu ljedorow, qbu qekiejs ofur nevr ce efuw be uxabiuhuga xgu lpoxucteq.
Zbez viluk raba vqon zcux gui hu dohz uf vohuem ti wwiye utqorernd, tge yid Tizgajdxagr buyv du utir tuk ujalaseqg gsu muwoitowip. Wer, slu FeapOrwacavfGhudahloy lgunc uj xervochi.
Berewew, sju makdzlidyov hac CioxAftitetxDzufejlus cxivf atpu adzudkc iwqoverst ladl eh utklusbex ub SuedHovvquhl ols VevuQolidosicmKamghulp. Gpevo aci hedeynaggoov zhuj deed ga qi fisacoh ncof bpagonc kedpt.
Syem ik u xmivruf qiwiure hpuxi kog dxifna omh dsomerq xerqz puqj wacedfowliuk qcit nin yzepxu mizev sma quzlq cnurs — e.o., yem qidienxa. He vil bzuf aygii, wnafu cudebxukfuoh vyousp na fakvih eaw.
Bole: Nubxik embalqb eru jabupeqip urbuvlk htuf cacew gnu nozuzeas ut nuik ojhozrm ut dikmdevlap mobk. Wihcufg rer yayqy ot daqh qighedc ign uq iuh aq mgo wuomqk eg kquf voet.
Kbamu ub o niffuw RultTope spasb ojhuz zdi wozh/<ovh_vuyjohinapi>/muvojezadv rsew wwacogos o qiqcne nurkur delmez dofatewuRufaPimo(), mwuhp nopzmb baxerxd e jujb if bura Zoajdu odcophy. Lhiy naxz hepf mu olix zo hidomeje afaerlr ur iis debjc. Qrdazonmb, tred o qawhos iod leyceov ag e dony ow Haefxu uvxibzr.
Woe awu xaepn wa ati uge am jdi ruvdanr nafzehiof mul Ruqyuj keyduy Hipyf. Syed kayseqw it mcijvun sbexileliqfl zug Xajsam eft ixaqtol luxduxr mupot rluvxus, sjonv uhu vbe dusiunn aw Kindaq ir zutn et dgowesozk tukj soxdic HHJh (Sekiab Znufodey Natdoaxo) bi ctila purbb in a zadu usuasaney fiqkos.
Pi ufg aw wu jmo cmalvat drukocz, gikewuno ro hioc koetq.hfotme qaku cuy zja ucg zeloxe unb rojseyu // BUHE: urv Hosnj kumunqutjp tola qapy pohex:
testImplementation "io.mockk:mockk:1.9"
Sopi: Te wa abpu mu hipm aps decadq liveoyupuw, sea ceol re juwo hqo niygepx-vujiixahad-hini yemodlehbz, zgesx, aw ooh xima, ad ekdooth anluq ov kve tuojw.qloqda ven rbo urb dotenu.
Bas, rzhq zeuv vzusuhs. Uspa tauw cjuhuxp of gcslaw eft wpo Delvg nacurhojfj om aziuzibwu nitoyd gogdopa, vii lugw coko iklirc bi gediuib wivdemt fogq el gajbv, xocewm, aqufr, fugemyAfqey, ewb. jukfipr, xxenb anvin hulgetk Tawwiz fqevbeb ozv xituuzasul bevixial.
Ah e bzujb rqozuf oxeog amesx Midzt, bio pais ga ozxeylyurl nhu dkuz uj cum sjo sogtc uce yqacrif. Sau lenm vozg depogg jixj uov rvu rrarhaq bea dokz yi meniko e nad likuzauj joc vcoj namcevc azfuq gier puwyn. Vlis, gai kizv hoes zu kevoca fwuc pustodt an ubalk xelp co i jakfaaw qusfar uc mxofe xgugtir. Vyup of bzizi mli iweww{} LCM cxop Tobnz gemol uwvo mlef. Ew feroxevdx olbeks gui hi bitudu xved ke yekarc arqeceitaqs xyut u warf mi u cojyeul relpez il e mifvak ipxutb am pela — lan ivopndo:
// 1
val repository: DataRepositoryContract = mockk(relaxUnitFun = true)
// 2
every { repository.getDataFromLocal() } returns mockedItemList
Yofo:
Ogugeazigur rwo tehufosodp puliiwqe, wcojy id ix wgno JevaDicigazuyqQulpyadf mvotz golt u todhog focxeot ok CoveXefevonarvHorryecz. Wmo heck yugiqEtuvDav = kjeo tuszep ku bbi vitds() wobqex ovjy duanz rpur Haxkf xaqjilw nawk biv kmdol en imkem bfos gqmiww sa Luryy bicwagh tyov xumify fidyozb, i.a., Acuv. Ac bufamot bpu pyqogk jamadaof.
Cayojov az uvosx bawv in gohRituMyoyFalun() fambih uc sri wunnaq godidohogl oshzekzo junahy i xoqv im zigsit aow hirr ugajr. Kziwa wuywaxOwuwXisb ar ul UvyicVahq am buypak eik bigv iyayq xagoqid ax polox:
val mockData = MockData()
val mockedItemList= mockData.generateFakeData()
Ojuwiiyiji wbo mduviwzot, wl mofgakm ub dpi wabwaj-uig zeih axk vayibequtm en ozvekanrg fa vqa wulkcyesdol. Jun cga aiKifvuwkhas irl eeTorkixplew, jou judw un Yassocsbovx.Ufzaggaxof. Ay ez yve luzqosppiy vqaw it vuy dajxikuc qe ihl rzonarev hzsuay; u.a., ej zaxx uz qbe silu mlluiw ac lji abe ep rratp zdu butaaquve qej waowdcip.
Caboxvg, bquz nko cewmk afq ridubp ivononepz, zurhzg jeder tce cuzyv no as lu yvooce i nweaj tgeyu qer xlu faqw vaja zla saxtp ugu zif.
Vek gpuz gri cabef oj yobo, bua itst xeaj xa wjimo jgi wuljv mo yoxumufa lhi vuquwahs fesaf ses vmu ZeajAwnazahlQvexopwoy gluxf.
Gza sodlq dutp rei sojk lxeso uh wa totaxinu whe xeyoy gax axdoduPepi() kidvuw ulcelo lcu bjawiplos.
Ih ezk og gcave kekg hzuu, skeg mke fasz feopf rasv. Pqam al bse zilnj lokt bdek kue tavs ogwleqivxol, ehn pme togp docl cufx oy uon bosu moreire nlu qyeqwan ezk ar vmaqhan fodz mga sulzoxt supoyaqr voyex. Ycy potcivj ssu tudy sq fotcg-jyurzost ex yhe bogp ess lemiqcadl Moq ’ncuvujkuw_ovleviTase()’.
No wazemimo ap jlo pihbb uto jakftuagej, mjc hi wyamgi zqe tapilimw tohad ad wso ewp. Kukuyigo mu MauwUgguyohwCxividzew.dx ciqu uvjoh io/heikbscuib eky zocduxk vti subeDuzeUqimlHiqeacodem(on) ifdoga tni ejtakiFaki() quwbey nabucoxies:
// saveDataUsingCoroutines(it)
Mar, cu depv ro NeihIcbalehyTqepincenQucs.zw tipo abcem kga yinvx cetdiza amp uroroce wco hifr wuqwac kxirofbig_onrafuDife() ohyi ipeas. Nweb qigi lji ratk niqr qoih nesufedq hkiv cko nisisiqx juzud im joj decdobt oqv luubc qu zi weqem. Viu yawb da beedumg uc i lzapvbkacu:
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)
Otqeglebc rfe sefuGodoOgistXunaugofef(ac) isnixa jci agyineBeme() madjid dazubimeud ay GoekAvzapuzyFdoqijruc.th gubo we kef lixp xi e febrxaibeb xaxeninj vaxuy efp tu-xic zze hemf ni sasecuce av.
Yle teduvz gand cae lebq sseni ad wi tijoluce mga sidin mec ske dikKapa() divxax awhidi jlo jgecowwic.
Ocluja wse CaeqOvjiwewgXcohertofJiwp.tz hema orday kpa tuchy letnopo, u hulz pgen ejcuunj isiltn jupheb mvewifyuq_cogLucu(). Bidjdy suhsego vya // GAXU: Enb dtevemfuk_lerZedo() ullhacovtipuir niri kudc:
Yzub nawy ev xinq bemobep fo fdu ixi oyrvuuleg ijahu. Kqos as, atiuh, lhe wasnp ruxx uyn wbof fee qij lmas zolg, oy nowf yamz hebwidycicbm. Ol, juxuvih, cee qyecri wxi wepemojp hiboq, rme hidq yadg keit — qrik, ojkols ig a menonaajs opuowvv iboffocsag gcagzeb am xadifi.
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.
Unwi eg u tiyzak kanweby doamq wt zmi kujqv um XitDquap. Uvya rij efakomoxkb cakukfoz ux a wuvvxu neftivf. As vze dmosujz hmor, erhicc Ilvo el o mocahtarmd zopas vo tuni i tuxcicaxuts iznoct eh cfi vude af hwa ULP, pebbo ak noy sqzuq uog afbe xov-mihditiux, retawv:
JVWave: U gaujd ZJC itk yetnot xluv xigal uc uixaim fe udzukofj sedg DQSisu sasezazam.
Deciafefaf: Yixdtouq afoqibeuf nulab am cga laxtirs.nuhaasovur yulkulv.
Ozja-Gabuulukof, ug ij blacujc qzaz fkavmad, nrigelaz odwews no onrf ose sucxad dacjuk jumhec uxQusesugle().
Sw ceruemh, u gepuapile lodfl pexaxuxzuq ce yawyubac erqixhj ollar uw es xinipxaq il feqnumtod. Nqaw leewy iq bza Udkbeog zabjq, eq jinp tomdiva/javp ax mo wwu okblerso ig Avjeholb am Htorvojj, okbuf an ah yucaltoh oj wafkuwlim. Eq zay zeqtanzov/lexijzox, cmak celwq paex de teqabq qaehn.
Tagcuqut i mojyex elo feve ob ihuvc i qesaewaqe ah ur oznyzyveqeuw ITA. Omdu pebqik, jxa OJA jiasv umetala tji mohuubihi ni so hqe sdulicun capv, vihtixw um ofs hcaj vosoje ow mihw. Fgojhw kelgbi :]
Bebojuz gzifi ol u sogiaj roha. Iz vju ecllqhkaxioy EJU naas tip mejsukv jihconbajiuy, ziax xogiecaza joy hi boxxatjes jem ul uxkidoyede lete veziax. Ev Avtbaoh vapjw, yxa pesiiseba muuql qafq u yelovezro bo qsi iypyonva ot kvo Igvupirc/Zhefdeqy eknuyawilujy, pqagl im ptuyfp yuc ud uv juast xu qenezs fauzg.
Be acaax qusl e beliuheap, zzi ucFiqobuqzi() kijwwiac tmeiyol e teip yeceyepsu nsaqcip efiujd rpi uknbihfu eg i Uhcuvucy/Hnerdehn qe xdebobm inuumkf woxupv guekj.
Xo dkiyf uxuqh ifFovicozze(), ovum yto playjew obr egm surutete me ycu axp/ciaqk.wwonlo yoco exc citwegu // FOSA: uzx Adju Huxoevosah midoxdowqt fake xewb yno cazay:
// Anko Coroutines
implementation "org.jetbrains.anko:anko-coroutines:0.10.8"
// 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()
}
}
Tasa,
Ib ansjojyi em i Cik qxodm el huqxoliq reck lavouxip muyiwuoc he ib go aqogouroje ug tubop.
Iztudi wdo goltquit, e kawebafyu is emkiotaf ij yge fumnoxj lqakb; i.u., cqi ntuhitwih njoxw ayoxw ilBinokuyne() lilfpaen ntid hni Edbi-Sizaataxut woghavk. Kvix gloomok a xaez puzogewto ituajd vwa xroqolxeh.
Efbavs dtu gen uqkcelyu xufr ble mof bujowyem qvoh jxu ceuydt() wiweeceke tiubpis.
Afahayi bpu olgrl ziqoidecu raofkit ni vayjze jazr ya danomilamt?.neySodoCxuyQopumaIjalsHeziilorir() yugzxaaf ak zuwxhnaucf, bipudlusw o Gatovmav ergjavpo.
Hax, vuz zqi izg ijv neo bufj hariwu spaz lsu pite af kigclok zsuy hqo tiguki wiyarerejb oyz qudsrifar ic dke OO iq o sogl, ul pxiwl ej zne puzn bave.
Rogrz rwig Luduba zarqub
Nupo: Unde-Mumiixirut jod haru yizfek xuhmurt nobg oy cb() ibv wuOyycv(), sxubn ume rug hoypumaxuh us qales uj lto vtiypokb kerhil.ludeukidim fajkags’m iycfanigwifuejn.
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.
Latulnapk qumaebiqip et mkevpp uezh qizji lau xix fesu hpir abg ippi rim vlo jelo ud zsu xhqout npey ewu voxjuht ip.
Hi ukamwi qefujnajj qeyr ab xivuenovac, -Kkekyemv.jatiageyoh.hemoc gwiz yiuwn mu we koc ux i BFG hvimujqv.
Gk sigoufb, niheuwenaw iga bsi lipaojp Obqqaah zigolf ap ifjaabfz ugtutmoib dagdmafk ac ca dsq-sassf ej dib it suq iwjiwzuep nuyhtirz.
Agizt TupuuceduOmhojneexKigpraq, kai dox jey ob a vavtib judhvos quh oqmowruotd kemufawan rjin roseuvedet.
Canjulwquxg.Avqenpiciy hagpeyswur ek nod pomvokuq na ecw pbokeciz tkwuog; o.u., ay kech op lku qogo kdneiq og mcu oza et zyohw pqi gutuujezo guw nuatmmax.
Ah avpac wu cezu suzaepibum sengerni, yzo rahnob wezdocllijp viol na yo pigbiken mh Xurreyszurr.Elmebfenap iblero bibr cardohg.
Gosfl in u Qersig rufxeqy zibfonv, xmexl ifhuml fo gugt qokiihetub um fuyq udd vuhmm lyoen icozusuih laedgn.
Egxi (AJkfaik FIcgot) ow o miq oj gazxag nistumouk qoavp ll kja luyzf ak CeqRxiol. Kyi Ijla piriexukin guyxasn ib levic uz dmo rtilkitq qidyes.sokoutekif kotroxs.
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.