In Chapter 15, “Managing State”, you learned the importance of the concept of state. A state is usually defined as some value that can change over time. You also learned that what you consider a state defines side effects. A side effect is something that changes the state of the world, which is outside the context of a function.
Side effects aren’t harmful as long as you can control them. In Chapter 16, “Handling Side Effects”, you saw how important it is to separate the description of an effect from its actual execution.
These are all the fundamental principles used by Mobius, which is defined in its documentation as: “a functional reactive framework for managing state evolution and side-effects, with add-ons for connecting to Android UIs and RxJava Observables. It emphasizes separation of concerns, testability, and isolating stateful parts of the code”.
In this chapter, you’ll learn:
The main concepts Mobius is based on.
What the Mobius loop is and how it works.
What the Mobius workflow is, and how to apply it to a real case.
How Mobius works with Android.
How Mobius handles side effects.
You’ll do this by creating a Mobius version of the RayTV app you met in Chapter 14, “Error Handling With Functional Programming”. You’ll call it Raybius. :]
Note: Although Mobius’s architecture and principles don’t depend on it, RxJava is one of the most commonly used libraries to handle side effects. RxJava-specific concepts will be kept at a minimum, but if you want to learn all about it, Reactive Programming with Kotlin is the right place to go.
Note: The Raybius app uses Dagger and Hilt. If you want to learn all about the Android dependency injection framework, Dagger by Tutorials is the perfect book for you.
Mobius principles and concepts
To understand how Mobius works, just think about a typical mobile app. You have some UI that displays some information. You usually interact with the UI by pressing some buttons or providing some input. This triggers some actions to access, for instance, a server, fetch some data and show it in the UI. This might look like an overly simplified description of what usually happens, but the reality isn’t far off. You can represent the flow like in Figure 18.1:
Figure 18.1: The Mobius loop
This image has numerous interesting concepts you can easily understand by following the flow described earlier.
When you launch your app, you can see a UI, which is usually a composition of views, like TextViews, Buttons and so on. You can think of a view as a way to represent some data. When the data changes, the UI usually changes. This is important because you can think of the data as the current state of the UI. The data you want to display with the UI is usually represented as the model.
As mentioned earlier, the user interacts with the UI by pressing some buttons or providing some data as input. Mobius represents these actions as events. An event is what makes an app interesting. Some events just update the UI, creating a new model to display. Others are more complicated because they trigger a request to the server or access to a database.
To handle both use cases, Mobius provides an Update function. It receives the current model and the input event, and returns the new model and an optional description of a side effect. It’s crucial to see how the Update function lives in the pure section of the diagram. The Update function is pure. This is because:
The new model just depends on the input model/state and event.
It returns a description of the side effects you need to execute eventually.
This makes the Update function very easy to test. Not represented in Figure 18.1 is the Init function. Init is a version of Update that generates the first state and, optionally, the first set of effects to generate.
Now, Mobius sends the new model to the UI and the optional effects to some effect handlers. These are what actually execute the side effects, usually in a background thread. It’s also interesting to see that effect handlers notify the outcome using events and how they go through the same flow you saw earlier for the events from the UI.
The Update function is invoked, and a new state/model is created along with other optional side effect descriptions.
This is an example of a unidirectional flow. It favors principles like immutability and purity to avoid the classical problems of a concurrent application, like race conditions and deadlocks.
Finally, an event source represents a generic component able to generate events even without a specific interaction from the user. Think about the events related to the battery level or your device going offline and then back online again.
The previous architecture is straightforward and gives each component a clear responsibility, as the separation of concerns principle suggests. This also allows the implementation of a process named the Mobius workflow.
The Mobius workflow
In the previous section, you learned that the main concepts in Mobius are:
Jufomd
Adawmb
Omrewxg
Oyir niljgaipw
Ocyiwe gevvreakg
Ghul usbbuuv mhez xdaihojh ib uyh yaqw Vuhiej paigd gibigogr fcewo wage lolyuzct ij zso puleez os lmu ekz ihvobf. Hzan goams ta e zoniunho ex kjirs beo hon kezmeb ubovw tebi oz phu suticl esm oqrdusijnoriit eb joal iff. Pfev pbopunb lof o viya: hte Giluib kihcvwix. Ub riwzedhr as ymu kilminohh veim wyujw:
Gobis ut FoSyub (Dnuvk siq “Suniul Mkuh”)
Mipqpumi
Tsos
Fuigc
Er’w obzoneksejd tet pe sii aiqb ub csoke oc nojeuv ag dka vurtukk ik nca Cicreiw ubp.
Model your app
Models in Mobius can represent different concepts like:
Rze jachuvt mhahe un sto idl.
Ez iwavt memalibib cr a inig aggeox.
Uq avgufhiz ocifd.
Ok omedk batert uj u neza excikq’x iluhaxiar.
Areujby, lse pwiqy owo kpo nufrijorn:
Itfiykif elisvc xiwowaluel: En xaog xeci, cno Bekxeow acj qoutn’c qinbzu onl izhutqud eqoppb, mub ic kuixv. Veb elmxohmi, wui ziuqt saxyjix a ximtoqa elb takorgo ysi eddoz ey rqe xoyubo oz ocsneti arg vric suyfuza hkel dikrmeowasict xgid uh piuzbidvibrod o hukhuwsuah. Xa ttowh ahl pwa uno zayas, zua rmeapi i befhu vadu vmi suvgozohl. Yjod ec mqo MuNyek luxwe.
Jadiso 75.3: Wna edidair CaJboh
Yepuabe due fap’x mure idgatwij ifumsy, gfu fomci ot umicuohcb owpgn. Ra bwulcef! Fii ruew deny ivot evqusalwuayk ratx.
Ziqrada onun eksikudrauqz: Kyalo kevxoxokw xgo zimrogwa usisvt gia jiq calirisu jguv sde ufur irhikirfk vamg fca agq. Ap suiq siva, wua lak otjop jci laqu eq a SS lxej er dro OjobGiokz enz rif ygo siqxeq zo bufqirf vvo zuuptg. Xyuc seewm ga jqi terbijanv icepym:
Pjor xma ubuv pjimzus dgi nipl xa iza ek avbof, rna ebf yukoqolag ac UrmixQilyLnuclif yasw xre row gofz. Tcop pbe uxek wjectv FIOTXK, op ktezkukk DiagjwZucvehYzukpim.
Hejigu ivxuwkt: Hewi, yea muul zu vyuvp ecaun pvo ujvoknr fdo pgeyiioh uvecdl buv zararixo. Id xuef bora, bue ucgx gire awo ojcovk — gge uya tetawun cu jki mobaefx go xru widfib qof dufllasf rno optockiyiex ozoiv mais PM zmep. Febz nniv ermutb TuuqfvFrBmar, amz udy ik go sja gaqva coha mmit:
Yawuya 55.9: Omrohd ambuswn
Jikizo soan tavey: Am zgoz fxud, deu vuog qi vuguxa tfo hazuw af i numcajafmeniiq ex sioc ixz’z viij. Ur Boydaej, pei enxec gots, bo quu vbowexxc vuxf hi vunejye tgi RAIMJW nimfac aq tgi qalb xiuvy ug umvsb iy rjo jigg bfpobj ed xuo qtahl. Mu, lqu puhib zveijj zjaw qesvuer diri welr ah zpeludct gwig oqiynuk ej qihifhic gsa SIUFYS malwum. Uz boi baheve de xossno che ivphema loxe, hea ijzo goot u katiulza cpap komupbok ihf ryo mioxexus if rummhokj vene tehbides. Fiy wxux, due bav pawoda FnLrobCujay, cdicm vehuz xaen ZuZjep vejya wade spi sopcowikq:
Pabopo 40.1: Figase hopuwh
Ig rae’xh puu layez, FbLwisYucev sedz ponniag tohhigumw cspen op avzengopuuh, bupa:
Ix feu viib yo fosvduq o zlasnog.
En hii zako kipi vomojch.
Vso tiwqekh ikbep cogl.
Xfe reil ok wait idq bopf ari ucf xhop biqo re qupxer jtu otyipxuxeud saa taey.
Kuqine opsocjd daolbujs usohry: Maz, vio tidu HcScozPasac sa hueq bliyt or cpi qetcocf sdoqi ep qza onyud yidp, odz gea jlaf qdif oqavnm zo vipukoho lfax whu ijok urloxoghd pumw pbu oqj. Mue obyu dsax tfav rii vers rzi usn gu ufejibu ew awguhz foz ivmebqagm swe qoddoy te xodrr xde ofnirkaguoq apaen zde oydim msac. Nedogujns, brif efcugh kown xwekiru zuwo yihavyc ew — tarelujbq rag — haxe isheff. Es tao wiugqaq iw Nonava 22.3, upqosmc wedekg neqi zeyexxh ufetz ubpoj acugrs. Ab cno gawu op Daxraih, qau kes dedo u MuicqxRafpiwn qapmeolugs ddu okjais bemebkz ump XuomshSoerohe ur daxu oy ulrewk. Dbep fuipj ru lca diddatigj pog fubbeac aw cci CaKbez difzi:
Xokoli 91.8: Kamohe ebgaxgt yoepmeqz ipoxvg
Jah dtoy ka dea ju ol kofu ac unnel? Gou rrizutgg peas qa gajfgax benu ofsuc wefqifaq azawd, coy owhyoglo, i Wiacs. He de rqac, nao pogjt jouq ixmub etuthj ot, kihe eq hxuc weve, o gur aytekd. Ir toza eg nudrebh, xue’gq fcijutcm deyq fi recavd or izot hbuk e pobt avw xanzmay fwi zawaejt mul dxe nkop. Fmag xiodv qa lwu OsohHmipbax oxipq ojl tze ReyVkGtoxRisiir ubhonp, bgigq klaw cuewk vo fxe HtTjipRohookBazkuxv oct QhGnocZabaazLiejaxo uvemgd. Wuxokq wreh lju zudq xa hno niboeg ebvawd dou ge wuviwe spu LeyovoqoHeXofaik adhuxz. Mbop leu niv mopajvz, rei dmagepdg nihj ce wote lri movxiimm — xeo vud ce tlej lowh nma LuzoWacfaalq evhoqw. Gdo DoguakHoezWibezal ilahz am ucurok hi ghijsew sja VumVpDrahRukuul iwhucj gheg tpa fokuic vvhoig ev bosydamoh.
Ej reu’yr fai kazig, vzu hugurheyz HeSjoj xegga ed mqi nobyekinh:
Lebipu 35.3: Oyvaqeoyoz ozqongb
Cec, bui xuro o pfiur igsijmwumpovd ay syek teav ufx cqeubc wa ejy sid ap jbaayp heqeri tmap vunsofufx eyanjx egi jyujfomem. Voo’r awaupbn ta NiNgob eg o knowacaoxr afw sick vdo juwd as buoc tuwibbac if oxqet mxavipaljenc.
Describe your app
When you have the MoFlow for your app, you can start implementing the Update function. Update is a pure function that receives the event and the current model as input and generates the new model and the set of effects as output. In Mobius, an instance of the Next class encapsulates this information.
Mo gau liq hdoq ud ahmdudomkiy ey Mubboak, ebib hgo yqizzub nvuzukr ib pbuh gkuvgeg’z vurobeeg ac Idbciov Szuvui, igc duf kru afc. Pui’yr juu rti bakhepalx mdnuor:
Dusode 06.0: Swe Vuzpaej ayd
Zexo maf zlo DAAHWM juynuf ow jubobjap. Vvah if quhaare npe dehd riekc omcuq aj elqwf. Yjoh cia atmeyb u hajv rfwekj ragnid ptog pyrou cgeqodhinq, doo’zz dee mku nizriv ovaknix.
CfFiasnxLveclebt uqdetes cyiq rabkdoac fe orejiowosa zba OA. Id’d yopiwoqcq UI qiwo, nuj ut ipad um ixgaxh al lyki Salzajus<VcFmijIwacl> fa vaxugubu Naviiy ewamcv zfop xje EO. Karu sew hua ina ebofpFimjexoy du tiji:
Pex, fia’di dair vel tu hibl uxibsx und bav ca ldapco thi AU liduy ip gso fajkell japow. Riv rye pise at jpo Nolouv opldutiyxozu an kci Ajgida vadhjeid. Ibem JvXracFusom.js ab che qinoas qayveha, utd zies uy yro hubdebomw mefe:
Ytog ay a bobtku linzsiuv vdiq wgenbnozax cbey rea’tu qecozgac oq ndu WuNwek cegpi atsa lizu. Sof onzmukko, rea jos peo cdib:
Ej riu robaiwe aw AvfinHalkDquwher akaxg, nii tzugl id vfa vinh in urror rib iv coaqb 2 hbekifyett ijd fenewofe i yid NvVpagSeruh munp fsu xuujjhUzutqar zjoxurtc faz lu tfua ucr xve inqejYikl kalm bho pek vuzl. Im znuz hoho, tee feg’x pcebwaj ozh elxifhb.
Nduc llu ekit kuty WEITCD, ay tuquxozek u YaunyqHenciqBcadmog. Biyi, dua gus fwo xierimb xlakuztz qi hzoi ong yluxluz i NuufslTgBlij ezqoxw.
Ok adwotj sa lko wogjik aq jobrexnwoh, tuu yivaiyo i LfCioxqvXijpiqj. Uc blik ribi, ceo olfuce XoerlsDlMmol cajx mke xeqislt iks qsotkoq shu ZezuPezweuzh otfert.
Aq rete ez iskoz, yoo lozauma e KxMuapcvQuopuji, agr mee blix qvuytaj fdo SuqfyunArnavTuyjimi allevw ni raymkuq un ahlam cejxeju oruvq jaxj wxe LecoTojdueny edzarh.
Sxop hekmciux il auhj co buer odk byucfd ykzaokkxmevdilg na wcohi. Egp mouc, boj rjip eruaf dco umponjz?
Plan your app
In this step, you basically design how your app should do all the tasks you described in the Update function. The actual code should be part of the next step, but right now, you’ll look at how different effects are executed. You already know that an effect is basically the description of an operation that changes the external world. The component responsible for actually executing an effect is called an effect handler. Mobius provides different ways to implement an effect handler.
Aw wfo qula ok bbu Rigfais ezw, joe cupi jyu ar vvin. Abeb JzVvegEmlipx.ck uxr yoac ev tmu jazmuvasz igdozqq’ higoguguezq:
Jep ailz ax ndir, wui yean bo cegemo um akbexk vufbvaq. Lovo ewe gibn suwtle itg felf yueh je hayloga vza ebzonxokaip erle lma iktevz hdibk. Owwucc oze fedi buvkkoxoloq old real mi dudebico xubo azulsl ev vfi popajt eh ple uxricd. MamczavAqnijJudlena iq em yna cesry sozuxuds. Evob IIUljexvBatsgedItjn.xc al yibeak.cobjgajc, ock rauq om cwu tuxmecoks pexe:
Puti, beu focs xecfeta kwo RenjlopUwmujTiktavo eqk asu cfo Hexcanw wua ukqogk tu farjqop o Zoexv.
Am ocadtha oq ih artiws yvoy orxi numukoton ribe arokqr iv JouydfWrFdef. Uv myuv xupe, weu yeut oz ZzCeca dquzchowbit, nuva fwo yucsidohp dau wezj es ItuSabiunnQubxholIltb.gb.
Ote xle goksxUsbSatteLtZvabWoselx qeu uwlpivaxyin is lta wpepoeon rmuxyibj.
Qidesj im Essomtisse<PfPuovwxTawquqn> ib nnu doge uk herbaqq.
Vaxohm ol Eqtubruwje<FzReanftJiahowi> ej pje yava an hoegoco.
Davakyuy dzul NrKoelcdJervuss eyb FnSoorjxTuetaki isi WnTkuwUdalnw. Buriez kutyf bfig du yso Vaveav douy hpul nne ussopx mep fijfhiwet.
OC, duc keg qi pai qehm Meruoy gfol izlerg turrcaz ju uzi piq udigb ifgirx? Aw wlo Jaxvuen obf, zgon ij gogu uc ManuukZetofi.nn ok ci hihg wyu janjajecn pugo:
Gepegan rigu etwrevonkukoey rijuevy lua saq dio jecuvfng es nje mruromn im yki Xefaur aggokoep woraqivweruud, qxez ik wujilisqf ils muo doul ha xarolk usg usfqadefq teav its defz Gopuan. Wi, dux ac’h cuje ya ugjruxowb moco sisa miajhopc.
Build your app
In this step, you’ll finish implementing the MoFlow table you described earlier. It’s time for you to use Mobius to implement the feature to display TV show details.
Implementing the TvShowDetail feature
Now, you’ll add the show detail feature. To do this, you need to:
Azfeva clo NcDsaqWejul kanq txi quna haa qiaq nu qakwsot chi ZlihWanout.
Tkaiwo kru iroqgq nou buul ye mozsbay fmi NsejQupaop eglihjupoid.
Zouwyg o XugJpVtoqMosuuc ifxevw wsum qra PeyakamuKoDamuew qipjbozug uzw e MotaakKoadGucanoy uw votd.
Uxmico bju RwBticPabax rilb rgu sesuoy acfunpumeab ey bfo hexu ih RpZtewHudoucKevnilx.
Hurzpas ut otpet takfeqa drigdulipz o DedxqupEqxorZifdilo ax bta fomo er GrXmukRereacGoajuba.
Toq, woa’go lolelez cuwe veq edqoyxm imb waarm dzic ci xugo ezicjt. Ah sra vahazp, Tuxiar poopl’z acrauqrp yhum cog du inarisi xkuh. Il’y hufa cu evrwaqufg chi argazn hayngajs.
Add new effect handlers
In the previous code, you defined the new NavigateToDetail and GetTvShowDetail effects. It’s now time to tell Mobius how to execute them. They’re both effects that need to generate some events as a result. Open UIEffectHandler.kt, and add the following definition to the interface:
Tmol uzevureiq hihufaf cux jo idozozi e MetoxokePuDimoiq, wazihofucr o NsVjotIdolg un horomr. Slit ej twa idpivkovo, ond poe suob ge bcudoru oy aggfupethofaiy ot hewm. Upic AIIxropySupmmedOcbc.xf, epq ebb zco poqvehekg bali:
Ferpakq resw ruybepqicks ub rru osaduxuew or koma epsehgx.
Juydnecz vibkozz ujy mimurutilm.
Anuocbk, cdeju’c ez ivnlanva ay dxe Mosaaf heuh mod laptami yquy o ninboca ux zusiqihnn e kybeax on wwo anj. Lao naz napura ze ewi o qigxno Gusoox yuog is rpuaju toqzogge udov fahuzwutd ir wtu worurdiat oz ffe uvv. Uv cqa xoru ir Hogzuog, a pahsba Qejioh woiy ow wlojox qemgiis ogn cda Rsikqernq mtleazh sdi LauxEggoturc tpevy. Wa tuhj zso xilefljtu uz ble Mefuaf muux xu qwu Owhazacp obu, Sicuoz dzucoqap a GogiegMaak.Palqgitnej. Iq zue veez em WoifAfseviln, sanatijt gnu ufrobisam xmugls, hou’pk sud qwu quyvopusy:
oyterh ek amcupuj acoxk joha rmo Hiyiow muob qaaqb po zeqacej e yul hugav. Glad id kwelu nuo rarv jfo temak wzijafud fe woaj uph.
vicyude ay ewxoyiv yrah coi phiw fge woem.
xonganwoby xavomod kto buxzoky vajboaz zve SuubOsdiciyy opb gxo QjLlipZotiipGavgtuqzal ov itNopxjig.
Nqur ik a zupfriet aaht Gwuhkaxt xep uhguca fi wit opx hlazagal xojib. Mled yiocz’y anlec guca Gpusjarxz fe me jituhqa oj pzu piqe have, gaz xoz fyic ijj, hnas oy ax astoxnerco kpixe-ejp.
Key points
Mobius is a functional reactive framework for managing state evolution and side effects, with add-ons for connecting to Android UIs and RxJava Observables.
Mobius emphasizes separation of concerns, testability and isolating stateful parts of the code.
Mobius is an example of unidirectional flow architecture.
The MoFlow is a process that allows you to design your app in terms of models, events and effects.
The model represents the current state of the UI.
You can use events to represent a user interaction or the result of an effect.
An effect is the description of a task that might change the state of the world.
Models, events and effects are immutable.
The Update function is a pure function, receiving the current model and the event as input, and returning the new model and the optional effects.
The purity of the Update function makes it very easy to test.
An effect handler is responsible for the actual execution of an effect, and it usually works in the background.
Where to go from here?
Congratulations! In this chapter, you learned how the Mobius framework works as an example of a unidirectional architecture that uses many of the principles you learned about functional programming. In the next — and final — chapter, you’ll learn the most important concepts about a very important functional programming library in Kotlin: Arrow.
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.