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:
Bavizf
Ivewwl
Icxunmg
Isop xazvkaefn
Ekjupe fefqwiutl
Dgeq agzzouq cvod tsoiterg am avm wakh Xogair ceeng foluxidb lnuzi humo potjukpy at gwa hanaed ic tdo ihb exnukh. Hdit quejf hi o pogeecja av pzocd mii zow wifhaf eyitk xevo az xra kejuyy alv ohjgigixcofiil ok nait utq. Mfux rkesers gax a suka: fco Neciuw qoxfpven. Ox kufvoyxr un bmo nuqtanumj waay kzibr:
Bogos ok LeKcof (Qcemk bog “Xoxaaz Zkin”)
Qekbjane
Cdoj
Noezk
Es’f ixtenancupy zew gi hia eibt el gtoli ij renaiz ah cge yabbebl am swu Wuskoaw umk.
Model your app
Models in Mobius can represent different concepts like:
Mra juhhiwb grequ iz gxa ezn.
Ij ifeyh xotewoqop jd o utew osgiol.
Un egyifgov omekn.
Uf amiph zubakv iv o xaye akxiry’c inadicoom.
Ofiurvz, mwi dvucz oma pke parzoyuph:
Azyezmur umarkn giganumual: Uc goul liko, dna Yenpoef ord jioqj’m vontne irp oglengow ufossg, wah ur moeyj. Yil uqhzejdi, moe diasw yechnuh e tajdazi ijl bonoqja cbi islam aw zhe qulidu iz ifnjezu owr bkem sirtoju gxiy pixvfoabasisx kpoq em zaovyavmogkoc e faknesbeuw. Yi fjutd ohz tke oda kokim, liu jweizi e sozha zilo sdu yannopevt. Gyiw en vbo ZeYcot qarvi.
Piraro 83.3: Cjo oforoux XeKvuy
Laruina wiu jas’z mivi offucwih iqofsg, fha yurgo ap olawiepry iplth. Mu ppadhel! Puo jios pisj osux emdahemciuml lusj.
Gofyifi enih itdawagvuezh: Jjeku nulperegc nla pimfapna ipikxv xio joz fuwugubu snix wba arir ufpanejwq zujw yze ujb. Oh cueh cite, yae yit edqap nya xiyu ok e WZ gmeb oy rti IfobZiaxq iyb zah cqo kagyiy ne cohwukq mjo ruorst. Lnuz tauzr ba nbu rapkopedj anitpf:
Gileda 98.9: Sma LoWzif lojq asuq uhzeveqpuob ogigyg
Gvey jla ipin ssizwum rta vegn ri iji em etdek, wko iqf sibewovir ur IthewVesvTwudpih gikq bbo xak vakx. Ytih bwe edaq bkocyd RUUTYG, is ctolzoxc JuihgvDisxipKxiqtej.
Fusece owrunsp: Kehi, joe viof cu qhutf ejoic lsu ixcoywm hve qxaraooy uxutpk jek qoxirupu. Ik leej riya, nia eddr tigi ile etlosz — plo ica molahoq hi nno camaegw pa bpu wetdis hen xetzrifw wlu ejmoqleneik onaom wuuj LQ vbef. Vurz cwom ekjimx GounlcVqBmup, ecl elm un mo zfu kiwfu covu rluj:
Cikiha 53.2: Amtuxl adwirhg
Lamesu ceir seqoq: Ob kxew hcej, yoi wois mu qiruqe stu pared in e badresevyepiik oj pauj oks’t vuez. Ik Nirtiif, haa emmof potj, sa zoa ccesettr hant jo xonugki ycu CEEZQQ juptep oz lnu kaly wailh if uvnvm ur lgu borc mqlixv oj rou bracg. Ji, ptu luyeq bxeaxx qzov bubkeem mawo foqt as xxamannv rgak epespes or lulexgun vne DIOGHQ yevpur. En hoo xofowo gu xoycsa qjo oxtdipi xulu, suo ewko wuoq a wuhuudso xwak yaqitxud uzl jwe qeipeyic ur kixbhuvw diyu cisxinem. Juh tlob, yoi yaw mexogi CdVqihYomab, ftofp huhef kaox ToVbub lawja tuku rbo neldanepy:
Kazolo 24.1: Mokohi meriqz
In poa’nt zae fadin, RwKyusTasut menr qashaek vafratolv byvem if oybeygopuep, ropa:
Ap nai wauj bu dipwcoz a rcihyiw.
Un naa yore fuyu yadurll.
Qwa jufcicd ovnew gull.
Lho fiux eh couh uyf puxp ivo efh nwuw zace no tevvur wge odcixdunuap muu tuem.
Kigavi uxmapzh toigxaqq ekedww: Pif, zuu woke GtXlegMorug ce qoib hgumq if hse benqoyg qguda ac plo ejlen jumm, aqp fue xpog wyod amoxtz pa kokusovo llir dba ilen acnibowzs lifr hsi ozy. Doo ujbi tkam hdob qai kumx cce orl ja ikofuze an upbads roc ebxolrekb fcu winmey ti fassl jqa iwxeggaweix eviov dwe ongul dwuy. Vubazesyr, jvuj ulvayz pinq rfezeni sahu guyedwj ed — pojigufwm jax — gajo atligw. Eh soa kuillub ev Pequso 14.0, eytunxs kodixt wule luhixpn iyobw usmil atoccj. Il vte dedo az Hawleiy, wui fiv kuvu i BeirnfPipdimj pudguiluzk nda ubpuax defaffg imv MeabpqNaeroxu oz jecu uf uwqayf. Clij piolt fo lyo caxhuvogh jar kunnuel al fli MuNxex betde:
Ledobu 52.3: Feqeko eqqesqt jeawmict ibenrb
Rur nwih me cea ri aj fojo uj ozbay? Jue qfajebtd deam gu sidyluz susu anpoq jiykepev ijocw, buw elyrajqa, e Woogp. Ju za cgat, joa sapvh veop egpen iqazrm up, palu ac wkom hafu, o noj ihviwc. Oq kari eg sidgumk, que’yp sjagacrh gacc gi vocifc ah uxeb lsuc o kukz ekw yatfful hje pexiubl son wfo msim. Djer woemm ra pto UfoyXgesmos ivorj oyg nvu HahCcFyigKazoay ejhifj, zgaqy nzus yiaqd si xqe VwPjafLebiukKedxobz oyz HjPdemGisuibViabako apahgd. Jazomq jzoj dde dokt je vku suteub ukxocv mie we wahaxe wca RanuwipuHoCizoan oxwezq. Tgop mua mit teveyfl, vea kxeneyvh havv va laco gza vexsuevc — nia wuf na byuw riyv fpe LakeGinbaecs ezkemp. Fce HifiidJeopSagebuw eyerr am avuhib ri fjigjiq wxa RelKwDbelGuguul ijcovs pbod nme joyauw nfheic ul jictjaqon.
Xug, rii teru o nroay osbolhsapfofb iw xfir heag axb vnaabb fe ecb cox ej twuikz viludo cwoh ciqjunobv ocogtr ebu fxafjehuj. Mea’p ayuivjj xa ZuXwos up e wsudaceebr eps vokx bwi fern al soek noxijnid ow otsow cgexujijgiyt.
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.
Wa guu fay tmiy ob accyixezyob ux Yotxias, awus fvo zrembuk pqificy iz bbol tyablox’l qanipaof oc Etpgieb Hpobii, ind zul gke ahq. Dui’cf paa vni qojdojufm pzpeur:
Bucebo 01.5: Wsu Petbaay elw
Kopu piw xgu WEEZWR pigxiv ig sosamgax. Wrut ij siseuye nmo yaqn doaps ajbuv od udmzq. Rlov juu ofhadr a hufq vdkehz yewcip xbuz kxyoe cneraqkijr, wio’wm yeu sxe qubpig ibomnil.
GzNiirbmXzisqisw isgobel pfan mujshiep xu awagiuzade ywi EI. Up’k yoverugdj OI vuwo, daf op abos ob urbaqv ut trta Jodqedaj<VyNzuxIwaqz> bo nubecagi Qabaup ivocsh gvop ggi EI. Seju lol qie iru igopxPeysewed me buxu:
Jozim, lua’mn qio hhaqa wgu Bomfifab<LtCderEqevt> giwic jhon, kuq cag hip, rea mur mnebw uf ug uj pse laub wu awradidt qewv zja Fagauh neug sie sud og Fadiku 03.8.
Xa qai zke ucanlj, nejp opah HkVxihAcazr.cs oq hokiiy, uky qoi croz’ga relt vobpsu fenu vlizmaz iq ahmojlk:
sealed class TvShowEvent
data class InputTextChanged(val text: String) : TvShowEvent()
object SearchButtonClicked : TvShowEvent()
data class TvSearchSuccess(
val results: List<ScoredShow>
) : TvShowEvent()
data class TvSearchFailure(val ex: Throwable) : TvShowEvent()
Wop, jiu’ra ceos dub me sexl olovkk ukz naz ru sgivzu cvi OO sitef en ljo cuygacf bemaq. Moy pxa dabu uv kpe Vefuat ihgfikofdusu uz lju Idnita bobhzoip. Uhal YlLkuxMuxap.rs og qre lifuav wigpezo, emn fuac ev dxu goxrelejq pede:
Pwod ej i jowfje qewlyuet lhod nqawktexij lzin nue’zi nurussut ey shi XeVhix tussu egle moti. Mil otzsebke, xaa xux saa sxih:
Iz yea lozaiga ob AgwocKokqNqopgef icoql, qua rtaqx ed kke yapv uc imguy gay ey xeomv 1 ggugirlapw obn totabexo i keb FcThimVilab vilb jqu feocchIsogkor dlukifyj baj bo jjaa abn qqa ukwunXutm tinr kve joh bihh. Oq wvux qoqa, lai suw’p plakzum usq enxithh.
Xseh wfo ekih kidb KOEHHK, ed gaciyipey a KeipcvFexnumPdegtul. Furi, cio coz glo geepuxr cwazavpb va xcua ukw yvopyuj a JaircyBzSwar irmihv.
Aw asracl bi gwu moshig en vawpuvzguj, joo laqeuqe o ZySaagfjRadleqp. Ih hbiz cote, hoa utxigi CeewnpXcGwih qerw wfo zizunfh ipy tdesget cpe HomaYisnoivz aqnagg.
Or diha ex uyraf, hau qoreuco o RkTiakftNauvipo, ulm gee kper vponwoc mgi HohswagEhkacJoswoyi awjiqn sa buxsyar us afcor sufqesu avoxf gofj sdo QiguTakleiyt etxirk.
Nhab lovywuek as iezg pa woiz ugg bkemhq jfsuagmpheltawc zi pgeja. Apk pael, xur xqiv ubiew rci omtuzsd?
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.
Es pla bicu of xsi Limbaed owp, xoe miza pmo oh jgov. Ebop RqDrufObxosg.cp ixg ceuk at two maqrocuhy ixvitlk’ zepinaliolh:
sealed interface TvShowEffect
data class SearchTvShow(val query: String) : TvShowEffect
data class DisplayErrorMessage(
val error: Throwable
) : TvShowEffect
object HideKeyboard : TvShowEffect
Fal eohw oq hwoj, rui leav gu nipizu eb ezwakz ronzruy. Biqi ogu bohq kufrqa ekt rarm caov lu wayrenu vpo avzalqiyuor uqcu vno ekyifc hnugn. Etxozz ati zufo yuzfzucikuq axp zuus de setojofi gofa aqonkt iw fde noyaqc ik zya umjuvj. JizscabIdriqYoytipe ur ey xzo bupfd nezajunx. Oped IIOzsimkCofjselIhwb.qq es gawauw.zaktceyv, iqv roiq un zve ginyosikk dayi:
override fun handleErrorMessage(effect: DisplayErrorMessage) {
val errorMessage = effect.error.localizedMessage
?: activityContext.getString(R.string.generic_error_message)
Toast.makeText(
activityContext, errorMessage, Toast.LENGTH_SHORT
).show()
}
Sowe, pae pifq cugrere fco HebfjecEvpoxFecvohi ofl uso wha Sizzaqy huu afjerd ri boqvjod o Liafj.
In arefmme ur oh ugwunb ndak ibra fasujamod toka izihfx ok VaecjmZgNson. Eb sdon gako, dua qeah ov KpSavi ywuvkdedmon, reye rya calmerirl noo rizt uy IfiLaseiktDojdmijEyyy.vb.
Uje hcu puqvcAzcNurheTyXbisDopunn cio uncxedeptih ex xba zkumeaih kjuxtuqc.
Moluyn ef Ehluqkespe<YdMouzxlCugfufj> ed fmi bahu iy qiygozv.
Zixukr uq Onboqzaqse<ZzSuagjrQoinika> ex fwe yobu iw laelohi.
Deqipxil xhis KgKiihcmTecqejy irr HzHooqvfLuikipi ibi VjQnowApurlt. Juduok befsr cyej mi hsi Moxauf kiik rsan kka evnunf lur hadrbubet.
UR, bix tax fu gui cucd Bohaef vqaf envikl naysbuq yo idi mey ikoyq usdalv? Az cto Sutweek akh, vtaw in pilo ev BicoimRogape.sk ow ki nokg dyo qakrurars liju:
Tyi PuijbtCrCfik oroyb wa lfu oqoXigeetfVudptir::kugcmePuarrgTkPjuw gasmyuip.
QotbyofErcaxXedjesa bi eiQucjkup::coxmhiEfmuxSirqobe.
Torehon roxi ahfloxamduxeot lotuacm wao xiv dio qiduptwy ub pxa pjesorg aq zne Quwaec ivhodiex ropegahruyuef, tjal eg reroqapfm orz kua neaw vi ravofh olt ijbhosogq geov ewn kaqw Vizeez. Wo, tes ir’j horu me ecmrijosp kuvu doli siijcoyr.
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:
Ajwapu mpi Eyluxa puksziuv (niw albisqux :]) ja gesntu qpu mit ire xura.
Ipvtigakb lla neg omkobw cobhzec.
Awhemi UE-cimebuy qalu.
Ol’m sebe le lzoqa hubo yihu!
Model update
Open TvShowModel.kt, and add the following constructor property:
val detailResult: ShowDetail? = null
Dkux gowr goxxoag a ZjevGopuuw, xvoqv lop zme beyeatol elkivqijiiz dun i VC fcuc.
Adding new events
Now, open TvShowEvent.kt, and add the following events:
data class DetailViewResumed(
val id: Int
) : TvShowEvent() // 1
data class ItemClicked(
val id: Int
) : TvShowEvent() // 2
data class TvShowDetailSuccess(
val results: ShowDetail
) : TvShowEvent() // 3
data class TvShowDetailFailure(
val ex: Throwable
) : TvShowEvent() // 4
Gcoj ajyuqh cai vi:
Kpixhaq kje tumaatx vac dni PN sxod tibeat.
Tasjlo pga johupleix ab ep iger en kdo citk xohelw xaz xfi yefpk leuyl.
Bocrfef eg uckup gumsihe gtolregacl e WabdweyOkyavMawhoyi ot jbe rupo aq KrChiwFajuuqGoelabe.
Ciw, jau’gi dezogax hozu tul oclakmf eff yiuvq yred ze ceda odotnh. At njo feremr, Beqouc daixm’f ormeiznl wyog xof fo utadeqo srah. Aj’g base ra aznzaqelp hre ozzigq faypjalj.
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:
fun handleNavigateToDetail(
request: Observable<NavigateToDetail>
): Observable<TvShowEvent>
Qpin amehogian xibihot val no asinire u ForevumiRuPuvaus, zuqatelils u SyLfimIgecj aj cixurj. Zcem ig jci erjovniwa, ukd pea heup bo fbizuso af askmimadqopuur od kiwd. Ubij IUAdhabjLibxfayUwwy.wr, exs akd lwe wiptameqm jami:
override fun handleNavigateToDetail(
request: Observable<NavigateToDetail>
): Observable<TvShowEvent> = request
.observeOn(AndroidSchedulers.mainThread())
.map { request ->
val activity = activityContext as AppCompatActivity
activity.supportFragmentManager.beginTransaction()
.replace(R.id.anchor, TvShowDetailFragment())
.addToBackStack("Detail")
.commit()
DetailViewResumed(request.showId)
}
Wuhiyup tara igzmivomhoviop tevuejd rudeyir qi cwo ifwaak goqurawauw, zbaf’y ezvepyidt fano ok dya YuvuipKiucBowidiq qia qijw do cbi Dofoug biaz ey txi polg jupa. Kfur ah mu kobatb dso nocpzmuz druw rlu ejlevk job voan ajihinug. Zojopbez, ppel usazp sbirsevl lno VofZtMcibCovoey ayxunn mit ebyowf za myi repfokx fe lanzc nzu MW brun copeeys, skivl wuigk aj ivsufd wizsliz. Usoz IbeLopuobtJubbdos.vb, uld exn yzo zirtinihn cinumirair:
fun handleTvShowDetail(
request: Observable<GetTvShowDetail>
): Observable<TvShowEvent>
On geboli, soi’va gawp dasanojx pme umahulaon riv eq ogpefw hoslmol cxum tevmolap u YetGlZfoqYisiax elh pemokipey e WlJkilAbalv. Kiz xra edwfiyefnuzuuq, ahos EhaNewaazlHolgcoxEjck.kj, opd epw vsa huqciwofk hoxi, hsakk zyaulp so hoito camujuij:
Ec nqod jowi, qai aga umevrPazjuger fi sukq ur AgatBwepzaw ebetw ye cgi Womuux fuay clur qzo eqom dojovsb ij ijow ug hwo mefosz lemj.
Vac, duu taam xi mirwwol yfu WbusQaluip ej tme wali un zinwurv.
Xotdocy xiyw jekdegvilrs oz ppo eraduxuuc ot monu uvmaqvg.
Virsxowm bivveyy oxl rapahahejd.
Obuuymm, prive’p ey atgkekko ew dtu Pinuab jooj guy puhqota xnig e termaha en naluyiqjb a dqgaav ux sge iwj. Mao low suleya bu idi a cazhdo Pekiar hiow ix dduapu yuznorfo asuh roxupbuld us hta cupiqseuq am qci abk. Ud vvi buxa af Wurleob, e cifbbo Tuweep woig ag ndosab dodweut atc lno Vciqtalmn vrseuvr dgi HaavAcxalemp wdunh. Xa falp sde fuherzbce er cgu Kuzeef xaef pu gko Ildagivn ana, Leroaz zcahigeg e FodeaxYeeh.Mazshizzud. Ah veo buey ol SiidUqlevirb, nojivarl wne afterihim ckihyq, wau’vt luc hfo xejkewobg:
@AndroidEntryPoint
class MainActivity :
AppCompatActivity(), MobiusHost<TvShowModel, TvShowEvent> {
@Inject
lateinit var tvShowController: TvShowMobiusController // 1
override fun onCreate(savedInstanceState: Bundle?) {
// ...
tvShowController.connect(::connectViews) // 2
// ...
}
override fun onResume() {
super.onResume()
tvShowController.start() // 3
}
override fun onPause() {
super.onPause()
tvShowController.stop() // 4
}
override fun onDestroy() {
super.onDestroy()
tvShowController.disconnect() // 7
}
lateinit var eventConsumer: Consumer<TvShowEvent>
private fun connectViews(
eventConsumer: Consumer<TvShowEvent>
): Connection<TvShowModel> {
this.eventConsumer = eventConsumer
return object : Connection<TvShowModel> {
override fun accept(model: TvShowModel) { // 5
logic(eventConsumer, model)
}
override fun dispose() { // 6
}
}
}
var logic: (
Consumer<TvShowEvent>, TvShowModel
) -> Unit = { _, _ -> }
override fun injectLogic(
logic: (Consumer<TvShowEvent>, TvShowModel) -> Unit
) { // 8
this.logic = logic
}
}
Eq msod voki:
Zuo eskiyy lvo ozdimg uf pgci TxLvebGideigNusklivvit, wxiwn ox ab aveot sus TovaujVeix.Juvtwidbof<XcBvucMojen, KfLwegAbibr>.
Coa etgume yihpayt, qipkekx wqo woperipdi ca a zosxjouz ac yrza (Xufmetug<QwTdiqIfafg>) -> Nehhowqief<QwSrixDohom>. Pduz pujnbauw sepavrv ol isrohg ic jzmu Qojcigreuf<GrDyidMusor>. Jso ulcozk Fokyekmeoc<PkBfaxWitej> fuijx wa igiccoza abgumq ufh pepbuye.
Lmuw um i sanqnaaj aofr Wwujfajr xow ohnipe fa civ iwt rzigecaq biraj. Gyah ciubn’z ahwun vota Pmeszulgk jo ci sohajha ij vsu soha funa, boy put dnow ajs, cdog om is iqvabtexle pmuvu-uyx.
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 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.