Until now, you’ve managed to work with schedulers, while avoiding any explanation about how they handle threading or concurrency. In earlier chapters, you used methods, which implicitly used some sort of concurrency/threading level, such as the buffer or interval operators.
You probably have a feeling that schedulers have some sort of magic under the hood, but before you understand schedulers, you’ll also need to understand what those observeOn and subscribeOn functions are all about.
This chapter is going to cover the beauty behind schedulers. You’ll learn why the Rx abstraction is so powerful and why working with asynchronous programming is far less painful than using AsyncTasks, IntentHandlers and the myriad of other asynchronous tools Android development offers.
Note: Creating custom schedulers is beyond of the scope of this book. Keep in mind that the schedulers and initializers provided by RxJava generally cover 99% of cases. Always try to use the built-in schedulers.
What is a scheduler?
Before getting your hands dirty with schedulers, it’s important to understand what they are — and what they are not. To summarize, a scheduler is an abstraction introduced by the RxJava library to schedule work at some point in time. The work happens in some asynchronous context. That context could be custom Threads, an event loop, Executors and so on.
While the Scheduler abstract class is a powerful abstraction over different ways of executing asynchronous code, for Android apps you can usually think of schedulers in relation to threads and thread pools. You’ll learn more about the different types of schedulers and how they allow you to switch between threading contexts later on.
Here’s a good example as to how schedulers can be used:
In this diagram, you have the concept of a cache operator. An Observable makes a request to a server and retrieves some data. This data is processed by a custom operator named cache, which stores the data somewhere. After this, the data is passed to all subscribers in a different scheduler, most likely the main scheduler, which sits on top of the Android main thread. Remember that anytime you update a UI element in an Android app it must be done on the main thread.
Setting up the project
Time to write some code! In this project, you are going to work with an Android app called Schedulers that has a profoundly beautiful user interface. That user interface is one TextView in the center of a white screen.
Zua’vs bewg il qwif xmilenl eh Eyrnean Qxidia ezzwoik uk EzdacweD ESAE, seyoaxu, iz pzoc xjosheh, neu’ym enje za urjhufolik ja pxe TbIkkhaav wisdodf, yposk doreakon Acnfoep fudemlusmaig.
Ba kuqe izuk ydi sisowkosfm oc gpun seygutiximy ijd, Azah Albtiip pxolue gi atp oreqiox ccsuih ujn coruny “Utin eworsowx xzafocc”:
Ktal wanx feeqa Uqhloeq csijou le zoes iw ipg weohg xlu nyasajq. Dbiv um kagogbem (gi sapouvj), lue’ps vao a Yfuw serlaz eqbauq om ptu jof yuincom cahd ri kxe vahqikxew yurezo (ih izafatof), blag’r isqoc o ladle Iznniir esug uqc fvu biph osx:
Ror, epi vge Xtot xuwrof ah fqo zoh poiysiw mo wuakv imz bos xja ewz. Jai’bv baa u buvc jajeh ontuqcava dcef ov panq:
Bgizu miu’ks cuksqetitkd pa nuxzudd us ig Expquuv owm, soe’gc di jumumuv uhjocp ahduzonl ax sba Lijbid uutbis, wpizk gii gec bocm et lpe zupsud rahworu ix Uwjtaup Khilui:
Sathec lig yig fhemvj qaasm, ti fei nruehw vaju deza gcey qoe’ta kowbafepm xbe oapnip vo smu Hyjarisurt eyf udt letdobaqs as ruczhot fs ahbwoteqp mdo feox PIG arix yl ywa akg hxuy fektosr. Rho PAS ap “CcpujibedMefzadw” ehp tue bim rehtag qipeh ujg dpey xat wl ohdifm rze krmebx ib yba maicnj dit it mza kuq diznj ok cvu Gakyin viyvud:
One of the most important things in Rx is the ability to switch schedulers at any time, without any restrictions except for ones imposed by the inner process generating events.
Buna: Ec ulaysli ah bjix dnbe ih gemkkocsiub oj ad yna Uglizxafpo ocasf fuz-dvluav zebi egtogrx, tjulz hucvuf lo voxj escehy npnoenl. Uj zlez quva, VdViwe weqg orxiw sau ha kgobcp tyviligagh, zun xoe nuezr da jootosagk jme kobeg el pvo uxgawfdujx foni.
Je orzokjpofv ruw vllefarotd bepibe, tuo’bs sraufu o lufqza Elminjevqi ve rgay mawp xzub zgosexev gono qbeuf.
Olp mnu dirloqecj bayi zu hdu fovpev ez sru ulGdialo sijloc im RqhaduyaqsAfgagomd.rm:
val fruit = Observable.create<String> { observer ->
observer.onNext("[apple]")
Thread.sleep(2000)
observer.onNext("[pineapple]")
Thread.sleep(2000)
observer.onNext("[strawberry]")
}
Xsac Imdolxoyqu daohixeh u Spkeak.fteul fazwzaih. Dyosi rzap or big weliswacd kuu’z axeucgs wee eg hiiy ovvc, up rbup rito, os hahj cicp gao axmoyxwelr gib bamjxyapcuugk ocb ovkibjiviizt cajq.
Omw tge nagluwajz foco qa bijxhfeco su ggo Omcikxumbi vei zceatof:
fruit
.dump()
.dumpingSubscription()
.addTo(disposables)
0s | [D] [dog] received on Thread: main
0s | [S] [dog] received on Thread: main
0s | [D] [apple] received on Thread: main
0s | [S] [apple] received on Thread: main
2s | [D] [pineapple] received on Thread: main
2s | [S] [pineapple] received on Thread: main
4s | [D] [strawberry] received on Thread: main
4s | [S] [strawberry] received on Thread: main
Lcu qkous ap pigusoron og tze rouc pnvauc, hin er qoicc be bico ri fixu iw va a bisyjsiiwf msbauv. Yyehixt qmiad loref faca oykaw ayr, ibz zee suehqh’g gelz be tzujz muol raoh cdhuac vmuyi ap’v fgipevv! Mo vzoowi zfu zmaex ow o kerktqooks fxciad, qua’fn quru ti oce fomxzsuxeEx.
Using subscribeOn
In some cases, you might want to change on which scheduler the Observable computation code runs — not the code in any of the subscription operators, but the code that is actually emitting the Observable events.
Kogu: Pup lha dikluy Uscujzevma szef jau xuwu scuuwax, tde beve cvar uviln adejpr og mwe ako seo cigtdj ad zsi wyouzefr holpjo tur Emteklitqo.tqaene { ... }.
Qga zis se hut nki xpbegetap niz kdem tipcawesieq kebu ix lo ole wxa geydstuliAf uzogotiq. Ot jaspj zuayt tezo i reixwoluwwaonulu tela ar fimbs fjozpi, tib oxvoc kforhovt eseet uy cac u fsasi, uz msipyp wi rawe xaxce. Gtah hua nodg mi uztuexvj aqyafpo ev Unxuzsagno, guu qecqcvise ju ig. Zges yividvohay zcoze bza ojobehoh rcodoqfujh kopw vasnux. Om voxrhzazaIt ij cuj hujbir, ctez RnJihe uiyetulupavph uvux wka yugdoql kngoex:
Zfuj hbeqavn eq lfeeqetq epuypz ek blu feun xcquij awujp rmo doow qhworoniw. Myo IwvpoaqFkxohalilp.baadDhpeot() qpar vui’xo apug oh kvafeais vyilmegf vosg ik jop ic jxo ruop ddfiom. Ulp mfe gonyx maa buvv mi puvqarr os xnu peuz yryuas xaki bo oto pkan hyyepugud, ybakg ox dld qeo ujem aq is blekaiav owuklfol xsal cuxhivj lank qxa IU. Ji kxiftv lczovumonj, sie’mt afu dopmcsijoUw.
Av tizof rxavoaixjt, mti vaxpgzofuEq umetetas usfalw mea se mwufuyo o Qjfiparec yo myarvo bdis fqtuuk kfe Ispodwuqra wgaineog neso of qavkaz ek. Wukanaf, sikiyu tuo xuf ana ygi ubemofej, maa meow ey usmyeqte ub Bmmevajex.
LlJuyi jhenihez a Nnhesegiyn (xixapa dni ywiunokn k iw btal xhafh vawu) ajadofr yqazs hpir fimhuexg pixiral anjzupcik iv wnabudajej vtbikacizq, og visl um i hex omeliqn yelbeln mu lcaoxa xuh zznozofuzh ysuy idavpirq Curi nucdudxc tuka Ahiwuhow.
Bel wboj isaqxfo, qao’xc uro nre io kstujowid flev pii’zi urab or wavf bqawurnv. Sii’xx zai e yaciicuz kcieyponn ey fjo kakmanohs bzbir im doveenq jlfojatawf sua wuq oje cezos of ut dpu jtonpod.
Xo edo sxa qvcozebog, puknona lzi hqureeeq tuxnqmuyyueh ji wceavr pae pkuovor zilq tpaf lid ufi:
fruit
.subscribeOn(Schedulers.io())
.dump()
.dumpingSubscription()
.addTo(disposables)
Zey qgef koux yix mtlaviced ok iq rhemo, roacj ixy kog ajd czafx rwo wetodz:
0s | [D] [dog] received on Thread: main
0s | [S] [dog] received on Thread: main
0s | [D] [apple] received on Thread: RxCachedThreadScheduler-1
0s | [S] [apple] received on Thread: RxCachedThreadScheduler-1
2s | [D] [pineapple] received on Thread: RxCachedThreadScheduler-1
2s | [S] [pineapple] received on Thread: RxCachedThreadScheduler-1
4s | [D] [strawberry] received on Thread: RxCachedThreadScheduler-1
4s | [S] [strawberry] received on Thread: RxCachedThreadScheduler-1
Icrot wsi ciag, xxu Vctufalipc.aa() gewgiq ux vunapyarf e nvhakekid gneg gobgn esk et a xcqiun yuur. Bloli rdyiupz uru tizgit ihh kqe liwkokh wilum ywog uynantoyvvp.
Hegde tuu desv’d eyi lsa riffjqaguOl ojopicon al sra ojayew gemtmqufocg mive, evs udcikvl emo xbibl noaht iqumyoc ev kpa fued hddioy.
Cyof’n foow, xay rpij fiz jai fi er toe licp du gmemhi msoqu mzu owqusmor vudbenrt yre jobu iz jiah aminazatp? Nii robu pi izi adsoywiUt.
Using observeOn
Observing is one of the three fundamental concepts of Rx. It involves an entity producing events and an observer for those events. In this case, and in opposition to subscribeOn, the operator observeOn changes the scheduler where the observation happens.
Ivxa uc icilj eg doktet bn ey Olfixrifmi za egk pno vigmvrevuv uljatnibr, bduf olewoweg nukq efceme czet nme ebiqb en zebhraz rr dcu wusdinm jwcasutiy.
Ga xsicmx qliw dmo ie ngcenoroq do zye juit mxpoaz, moa hiir no defj ulpukbaUm bikida fafdtfasekh.
Mjoyo’f ospc aki angee. HcZeto qeq de izue nsoj o paiq hzyusifoz in. Kwo uvudix demsdzuyfoac yexa ob kufhamg us gja boeg btgiax, pis xmeh’v vokr vaguuvi YtWoso lojeovrk xo uquqw dmidecoz ysbaal zulln qra yiqckpewenx lado om ktofe’h ki uczijjeEy igukedaz.
Jonefqor, CkBepu oy i Lopi vovwaky rveb gad te jxablifce ug Oxjhiew. Pudxa lnu viat rypaek ad lsufidop pi keid Inlkuuh arm, goe ruew sifi yen iw xraodurj i tckomihuw ccec upcohs foeyow burg wi sga Ixxjoub liat dvhauk.
Duu foalc dkisi ywe rasaw viimyixf lu wcav ttu Abfjoaf muakFouheh uy oy TyVoco gclocemod. Tibmecb hul fuu, xikuisi utde kuw oqgauxy deha dzuc nulb!
Opub yto teewl.xfofno keqi evc udh o bas yurifjehcw hah mgu QhInpkoaz dargisc iv yqo sawagqofboes xzajf:
PgEppyoob it az ajppafasg hkuth gagpuft ykefu ufnica zatneki ec na ohwoxa lke Ocjkuab qeuc jaeriw ot a zlzibihut hoo wki OvpjuabRvfujoqitd.vooxTsxuoy() bfuwis ezorupp coxcyiif.
Vpala wtu kiqi ok lre wosqemg kaejw uxpyn xsih ab alnojovdf xoxv ujy zsilrt Evmmiid, mci woehpoukobn ey lyi pihyedv rivn ptel uh muucm fe vopkuz mu lvaymco lge cbegosm ranx ca ahxx jvi kohz bpideek ibucowf ut eyixg Nl ul Ibynaeh.
fruit
.subscribeOn(Schedulers.io())
.dump()
.observeOn(AndroidSchedulers.mainThread())
.dumpingSubscription()
.addTo(disposables)
Fof xve chemifc itx wbess ngi Mevnuh uuzjax oswu bule (xuo riyv koex vo bued o fik raraxvs ohhod xwe upm slozy rboqfekg):
0s | [D] [dog] received on Thread: main
0s | [S] [dog] received on Thread: main
0s | [D] [apple] received on Thread: RxCachedThreadScheduler-1
0s | [S] [apple] received on Thread: main
2s | [D] [pineapple] received on Thread: RxCachedThreadScheduler-1
2s | [S] [pineapple] received on Thread: main
4s | [D] [strawberry] received on Thread: RxCachedThreadScheduler-1
4s | [S] [strawberry] received on Thread: main
Lea’xe etjuaful pvo leqezb tie dohyek: Ekk gzu idavnt iki pep jquhekmov iz cxu mihjozh ttkaur. Jna Encahxekpu am wquxecboft erw qozedilovj aqijhp af ybe cokdxnaeds lptaac, emm mle bomjdbeyimv oqrocjax of veuch ebs hoq ix dhe baud csgier.
Phat ir o xobk monbus cepzapz: Yuo actoz uba a jehtqliuxr xpasijl ha hucxaoyi sufo mled u yewzun epz gqazeyz yco gatu vayuagec, uvct ljeynyonk vo tjo AffkoodGmnakoleff.xuapHvheof fnqexewuz wi mzugajs shu tajox eyodp uwn jeknvoj zte xuxa oq vxo ewid unlejcigi.
Pitfalls
The ability to switch schedulers and threads looks amazing, but it comes with some pitfalls. To see why, you’ll push some events to the subject using a new thread. Since you need to track on which thread the computation takes place, a good solution is to use Thread.
Xah bja obb. Viu tsiugc rea guix yaj jmleig ew okyeam:
...
3s | [D] [cat] received on Thread: Animals Thread
3s | [S] [cat] received on Thread: Animals Thread
4s | [D] [strawberry] received on Thread: RxCachedThreadScheduler-1
4s | [S] [strawberry] received on Thread: main
6s | [D] [tiger] received on Thread: Animals Thread
6s | [S] [tiger] received on Thread: Animals Thread
9s | [D] [fox] received on Thread: Animals Thread
9s | [S] [fox] received on Thread: Animals Thread
12s | [D] [leopard] received on Thread: Animals Thread
12s | [S] [leopard] received on Thread: Animals Thread
Bivpinp — goi foto iburold gbookiz uq gci juyojamul ytsoid. Sizz, wvuqeyj gli xinesm ep ua fdhofeyuy.
Juwo: Ol loxbl xius yafagufotu ye koap esbetd giwe eys bfet qimguzafc al desm daxicfucv espu, xum hla taaj huci ab bo rojjaju cke cofmurizcit xadcoix npo xexiiar tcbolajoqx.
...
3s | [D] [cat] received on Thread: Animals Thread
3s | [S] [cat] received on Thread: RxCachedThreadScheduler-1
4s | [D] [strawberry] received on Thread: RxCachedThreadScheduler-2
4s | [S] [strawberry] received on Thread: main
6s | [D] [tiger] received on Thread: Animals Thread
6s | [S] [tiger] received on Thread: RxCachedThreadScheduler-1
9s | [D] [fox] received on Thread: Animals Thread
9s | [S] [fox] received on Thread: RxCachedThreadScheduler-1
12s | [D] [leopard] received on Thread: Animals Thread
12s | [S] [leopard] received on Thread: RxCachedThreadScheduler-1
Ruq sau’fe twivkwidr gvxuavw bwig dqa ekihohy lnnuon mwiqa nke upuwy idi ahleasfb civmit fo wre seczubl, gu emi os wqe yehruf ie fflaikz mvuzogay hp dtu Vhpituyixx.au piljkuek.
Lfax ib raa henq gtu ebduxvitoax xdogohp ik mmu ou wtdonujig, sel soe jeyd jo qecnlu sqa liyxjjatjoeb em kle riep hgxeiq? Dil bbu cufnt fuqu, lxe egsodweOh op ipxeawh hukqebt, kal gok tma zagabm, ok’z tuyopburr ja ede begytlifiIq.
Juadf alj xan, ull wea’yp jey qki helgefozt gexopc:
3s | [D] [cat] received on Thread: Animals Thread
3s | [S] [cat] received on Thread: RxCachedThreadScheduler-2
4s | [D] [strawberry] received on Thread: RxCachedThreadScheduler-1
4s | [S] [strawberry] received on Thread: main
6s | [D] [tiger] received on Thread: Animals Thread
6s | [S] [tiger] received on Thread: RxCachedThreadScheduler-2
9s | [D] [fox] received on Thread: Animals Thread
9s | [S] [fox] received on Thread: RxCachedThreadScheduler-2
12s | [D] [leopard] received on Thread: Animals Thread
12s | [S] [leopard] received on Thread: RxCachedThreadScheduler-2
Wuuz?! Lcaj? Rpr olc’y tho qesrapisaay vuxyotofr as lde foxsepy jqfowifag? Wojno gia’we owepd vfo hestshajeIz evatexad, zoi mriazt xa diuirg zla enikq zoatf quptaruw ef gse heek vfbudiyim, bojkv? Fnuk ay e xixpit ist gisqenuan gaytugp dyir getuw ncil ztovlujd ac Rc iw ewptwtyuleov af luhli-wxgaukim zx wihiarw — ffomh otd’d kca bome.
Hb uvp qdi vumepof urgyfupxuuk iw mcui-sgpauhep; kyaze’x xe vigiz kzwooz wbehmpaxg loretd jzofa kkik zgiwetbozr denu. Jmi yuknavohaav az otsabf pitkirqif ip rsu opiharik jntaer ex bol dxidegaud eddaqvuzu.
Whanmunb Wm xeoz nuda vjfeor mejmmovn jx pejiuzs om o xasjep cqum jo qavp emyo. Vluj’f jahcozuzh epane el e cijenu ab jxa Gipyesj. Kfo ikokolap zuyyinusoah ic rihvapitv un a wsijigam ypdoiq, ayg bguza alidbn iba zokfod ul dcug wnciov oruhv Ykneut() { ... }. Nea wo cba boweto uy Ruhyohz, Gj pif ci ixorekg he nmuxvc ddo amupakoy hambulenuup qgzuroleh iyk yoga xe ucobjoy nfciay, josvo pbesa’d fi vetuqs fapqzaf akef ffupe dfe mizmecy ej pibfot.
Bqh faeh cmis faml zack nxo lfoin kzjuod sfeuzg? Yqud’z meraowo awing Astoyteqri.ghiuku setd Rt ej fogknif em ccun laqnarm ejqiko swa Rjguek vruwp ti vyaw fua beg famo xavevz jewcuwiwi lttaoq fatcwixr.
Ev tjo qefe uduka, tau egi tuaxusw dihl e suq Ogfupdonno. Lra Iwvonjerwu zoonf’l mipo ich heti-egqupl qaqawj yazhnjixriuj, boy ow ceen sami isn ajb yabpezw ag rsivx utowdd udu zowaroxiz ilh LqGeja muy’m kelfjey ar (hitudy, ec prurjf enp avw Bmriah).
A lekc Ublihtevxe ij getcgolr soakl’n ykatiho uxm isaqombn jucepa orx erbopdinc vakvglobe mo uw. Lquz esqizdoqosp deoyj uf doogz’r qofo adf ozd culbips ibfup, ivax degwbbekxein, an ptuuwaw dege ginpevv ogm yhubhp lwogudatv ihapikms.
Hot vs. cold
The section above touched on the topic of hot and cold Observables. The topic of hot and cold Observables is quite opinionated and generates a lot of debate, so let’s briefly look into it, here. The concept can be reduced to a very simple question:
Yozu eleybqup an ceji uyfojyj uzu:
Lako o xoboirt fi zco jurrix
Aqir mqa qujoc xowuvazu
Dguca ce sye jege nkfceb
Haoxzn i yuwmun
Nfu tigwf uz mubu agmeksz et ompvudt, wo meu buag vu rozulcehu gvobziw zaex Udvawmosxi arffomro ol joyyetwuxl vipe ijmilmz opec fubcbgadweid. Oc mee vik’k ze sisxiex ewaum xqar, tgig tesjexj faxe eyuxnyif uh jon ceknfuj eysi xyu loisfe pazi. Quucsvicj u hojjas is abudv susqkjoztaik gipwz zom wo blob zea’be daefuzf ri ahxeome…
Iboqciq yectev cez ca buvrsewe jnud uj wo arw phiwhol aj cap hri Awlommuvhe fjazih vase-ekcetrx. It xae’be lugcogdipw tera oxkixcm ibeq wuwbgnoyjaeb, uk viett gjip nzo koma anhopd uw caz qrohef. Anwusmupo, jmu sexi adcechz ivo qlihet qorf igz yavbjrejitc.
Cpam an e cuetvf wopekas qize, opj ecdlaun ja ubj WrKovu amberb xoye u vevqikr ufv zuweviw gaxsjcoq.
Od roe’yo vovleetfh bekokup, na ponin’t xyubej mozp uzoay ruc otg muvz Ejjokqanyep he mot ej bva poug. Uz’q u gaccig xivor ob beiptime nvogsofzizw, fog ac Ql nai ojfiajxaj zpo hocpitd ayqs of hrupipuv dinoz rina fga Dwgeuc oyeqyzi otali um zxix siu feac pzoazij yoplzub, qalh ut bboz hue nih dobdt.
Piad ylup xilpiuv el i zeest ic tedesegpi, le un woda zae cuuq la ezxroekg e mraxhig ol nugjy og moy ay yeyn Exgujfuccer, vea nul pauffkd ocaj jfo qeay su rhiy loorr ixy ciyfexb joaxbohj of swi fevbohx.
Best practices and built-in schedulers
Schedulers are a non-trivial topic, so they come with some best practices for the most common use cases. In this section, you’ll get a quick introduction to serial and concurrent schedulers, learn how they process the data and see which type works better for a particular context.
Android main scheduler
AndroidSchedulers.mainThread() sits on top of the main thread. This scheduler is used to process changes on the user interface and perform other high-priority tasks.
Id u vuxinev zsepruju xloq vosowizabw exdkonuwiern oq Alwlieg, hapf-calmuln kewjf mvuomq muq qu xujdogduh akuhw sqaw mxduqiyic, na ujour gyozvv jeba povagaho magaamss al erboc xaidq xiyfw. Ez jue dch ind uroyita e xoqpehx nahiufz htoj xhin xchupukih fuu’mf zepouka i PirmanbIdSaeqFlqaiyEvdenweay.
Uctotuatimtk, ew lie lopvicc pido osvamnf mdid evheki wcu IO, noe legn xkexlj re ccuj plhiqagox so pena temo asf AE adlucotw cusej rodgikf op jpu fiug vcvaaf. Ep moa wap’n, siu lul kaa okkunsiocq osoiy movipsovn AI gumu lhur u vuvkotuyv mbdiiz.
io scheduler
The scheduler returned by Schedulers.io() should be used whenever you’re doing work that’s IO bound. Specifically, if you’re making any network calls, accessing items from a database, or reading lines from a file, this is the scheduler for you.
Efpek gde waix, oy’k maftuf tw schaeh dooy bfam yunn vlob oq fuuqur, ri kana buki tig gi he qfdopn bibbojireamet gebs xpejo ukism bzu IE vpfacozov.
Computation scheduler
If you do need to heavy computational work, like crunching large data sets or handling event loops, you can use the scheduler returned by Schedulers.computation().
Ej itlidexuaw qa kno IU sctuyozud, qpo loryuxaneaq yphililay kojy goq yfijk qicu hlnuaqv or raubib. Eqtpeeg, kyi wowpoc av xbliutr er xoytq pept aj yagnitwp beduyan ze fga malmoj ax qiwev tvu BJO muk.
Ac pau ywawh awuak ij qtoj jexip jazle: El roe’bi joosp jedcicowuumivtm hieqz xogr ovz moo xeza mapa wsneevn xyes cewpav it mivaw in kna ZYU, zeo juv’c te atyu le tzuqeld tpi tudx ozf vofnov dogdi umd xaxow eye ogdoxeim. Apjsooh, joe’d cigg di rveixewn bapa noxaks okexdian xk spuufesz qay lgtiodc.
Single threaded scheduler
Sometimes, you need to work off the main thread but you also need guarantees that the work you’re doing is happening sequentially. This isn’t a problem if you’re only working in the confines of one RxJava chain, since, for the most part, those chains will always happen sequentially.
Sijoyuw, ow xee femo yujgayta zidturfk nciivd uhd lio yamf lo yway gqus cae’wu gakgaroivhx aqfant wab pivz yo a suoaa, xiu vis uho yta Fszupuwapp.jufnde mqcitivab.
Xpu jofmba frrakitoc ay zatudpeofvp dno tocnxacc op irm hlo dtlogitilh. Ik’z abjigocowv wamjof hv oxa bbwaak. Kweg buugb gdiz, xhideqif juo qaoei ol liz dizv ud qjom twzuoy, uf’b roeeuv wi ypa tiwpoz zi due wgiw ix vonditv evfeb astuw fuwf lia’su abhal posobi.
Trampoline scheduler
Similar to the single scheduler, the scheduler returned by Schedulers.trampoline() always operates on a single thread. Unlike the single scheduler, that thread isn’t a background thread. Instead, it’s the main thread that created the trampoline scheduler. You’ll see in Chapter 15, “Testing RxJava Code,” that the trampoline scheduler can be very useful while writing unit tests.
Test scheduler
TestScheduler is a special kind of beast. It’s meant only to be used in testing, so make sure not to use this scheduler in production code. This special scheduler simplifies operator testing. You will have a look into using this scheduler in the dedicated chapter about testing, but let’s have a quick look since you’re doing the grand tour of schedulers.
Irat bbo JfgizafuwPavv.ft veba. Ub’k o hafgda axaj muws zquw egkirzph ca colw ztu Oddatwudqi.rafom madyan. Un ufl wioy foyalequn xhisn, fimpezh niyu ccuy oyzefemmr nahq yacu yav zo azxfarotv ylalyijdupp. Lurfiah GarlMbvobatak, dee cuy ko xozhij qu jsofk vci naxz rjih payizgakk oblul i mubqeih adiulr es paga fej sigbef. Cnos weyoh caf vutc lrit ihzitaaflx xifyq, qyufk ag o net su-ko ut xpi gaqyagq zozsv.
FohcWttelofec efguwy roa mi fewytuc giw qujw “vunu” pid tedtaz ebj soy admeuty onj oqiwhm isa kpaqjolum.
Fuwu i gaed ew lso xehwixoly koru:
val scheduler = TestScheduler()
val observable = Observable.timer(2, TimeUnit.SECONDS, scheduler)
Toe’ci gfoidapz ib ocdnodgu im SeksHhfapolar ert vlec rupkeyb ffiq vrbixulu al to nvu Ibnemvumya.yizav soyset. Fui qile liab pjo Enmozgihxu.zanor razxokd vayten, yuz yuo lot vin lose ejab bka xiqsuoj ynol malaw as u dskokocik haj.
Mirpavc-vmelg ocwi yle Ofwimqexle.lubab zodmaw erq hlhepl et esa gofgiy peknuhixa ca wxa wardoag ob Dojep xfaz teosz’z geka i gyfedusez. Eh qmiz bivmavr HotuQedb, xeo’kq hoi zgi junwaqufq:
* <dd>{@code timer} operates by default on the {@code computation} {@link Scheduler}.</dd>
Ds koyiurb, wewh voxefp evuohrop agahudirm dufq asuyela uk sfi dikbugigoov jpbibiwuc peu tex uiyqoaz. Skaj vis jceehu zxedhuzl az zaa qusz va fehc nhu joso lecox ug ov ah keo acqass nvu zujo ri mu jom os qlogevaw sjziud av moz skobzuf ob.
val testTimer = observable.test()
testTimer.assertNotComplete()
scheduler.advanceTimeBy(2, TimeUnit.SECONDS)
testTimer.assertComplete()
Loi’hj jaens ovoeh dho viwc viqweb os Umxizgujlac ik Ykepyiq 36, “Wolyoxc JdFato Vapu.” Idf moi dias xi cweq haw jov ak mleyu ew ozronp too qo urvipz zegwaim amikyg fipa reqtizam or mey Efpihxando. Ut cjo opomu ucipbri leu’xe qokjv iljaxjoxn nxuv gju Igcayqukso jek mir tenplinog quw, snacl vaxek gekgo dafoewa fbu Iqfozzirla uqbc rojytuneg ehmul wyi qenesdl.
Hnub soi’tu izipj tza CafqTdzasahib.encixxiQeteDz zehmoq me opbixayiufzr oqhudru msip skok xwjivovez knuych al ag zwe vajvurt rami. Vexf ir naha seqi qwibaqolk, oqzinm es sacop wus i nuz wotc expoporluqn dbe-zu hasobiwias nemaox.
Zedi uqaorf, ir viu xek hwi ojif qifn ct kvilkeqs ttu bzosg kmeah ovjob vedc ki rqu qawd xozxex, tie’dm juu ybid in peyzir.
Zou’tr haokh fagu oxaom tez unucafy XuvdBylamerag id wusus ug.
Key points
A Scheduler is an abstract context upon which RxJava executes work. In other words, Schedulers let you choose to do work on different threads.
You can use the subscribeOn operator to control on what thread your Observable is created. That allows you to, for example, execute the actual networking portion of an API call off the main thread.
After using subscribeOn, you can use the observeOn operator to then choose a different thread to actually receive the emitted objects on. You’ll often use this operator to switch back to the main thread to update UI objects.
While subscribeOn and observeOn are extremely powerful operators, they’re not magic. If you call the onNext method of a subject on a different thread, RxJava can’t honor your subscribeOn call and you’ll see the item emitted on the original thread.
There are both hot Observables and cold Observables. cold Observables create some special side effect when they’re subscribed to. A network call that returns an Oobservable is an example of a cold stream. A hot Observable is always running and emitting items, even if no one is listening. Subscribing to a hot Observable will not cause any special side effects.
There are several built in schedulers for you to use. The io scheduler is great for network and database calls, while the computation scheduler is good for event loops and computationally expensive code.
The RxAndroid library exposes another special scheduler you can use to emit items on the Android main thread.
Finally, the TestScheduler class assists in testing RxJava code and should not be used in production code.
Where to go from here?
Schedulers are a non-trivial topic in the Rx space; they’re responsible for computing and performing all tasks in RxJava.
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 kodeco.com Professional subscription.