In the first chapter, you learned what dependency means and how you can limit its impact during the development of your app. You learned to prefer aggregation over composition because that allows you to change the implementation of Repository without changing the implementation of Server, as described by the following UML diagram:
In code, you can represent that concept like this:
class Server(val repository: Repository) {
fun receive(data: Data) {
repository.save(data)
}
}
With this pattern, Server has no responsibility for the creation of the specific Repository. That syntax is just saying that Server needs a Repository to work. In other words, Serverdepends onRepository.
In the second chapter, you looked at the Busso App. You learned how to build and run both the server and the Android app. You also looked at its code to understand how the RxLocation and Navigator modules work. More importantly, you learned why the architecture for the Busso App is not the best and what you could do to improve its quality.
In this chapter, you’ll take your next step toward implementing a better app that’s easier to test and modify. You’ll keep the concept of mass of the project in mind, which you saw in the first chapter.
You’ll start by refactoring the Busso App in a world without Dagger or Hilt. This is important if you want to really understand how those frameworks work and how you can use them to solve the dependency problem in a different, easier way.
Dependency injection
Looking at the previous code, which component is responsible for the creation of the Repository implementation you need to pass as parameter of the Server primary constructor?
It’s Main, which contains all the “dirty” code you need to create the necessary instances for the app, binding them according to their dependencies.
OK, so how do you describe a dependency between different objects? You just follow some coding rules, like the one you already used in the Server/Repository example. By making Repository a primary constructor parameter for Server, you explicitly defined a dependency between them.
In this example, a possible Main component is the following main() function:
fun main() {
// 1
val repository = RepositoryImpl()
// 2
val server = Server(repository)
// ...
val data = Data()
server.receive(data)
// ...
}
This code creates:
The instance of the RepositoryImpl as an implementation of the Repository interface.
A Server that passes the repository instance as a parameter of the primary constructor.
You can say that the Main component injects a Repository into Server.
This approach leads to a technique called Dependency Injection (DI), which describes the process in which an external entity is responsible for creating all the instances of the components an app requires. It then injects them according to some dependency rules.
By changing Main, you modify what you can inject. This reduces the impact of a change, thus reducing dependency.
Note: Spoiler alert! Looking at the previous code, you understand that Server needs a Repository because it’s a required parameter of its primary constructor. The Server depends on the Repository. Is this enough to somehow generate the code you have into main()? Sometimes yes, and sometimes you’ll need more information, as you’ll see in the following chapters.
Currently, the Busso App doesn’t use this method, which makes testing and changes in general very expensive.
In the following sections of this chapter, you’ll start applying these principles to the Busso App, improving its quality and reducing its mass.
Types of injection
In the previous example, you learned how to define a dependency between two classes by making Repository a required constructor parameter for Server. This is just one way to implement dependency injection. The different types of injection are:
Mezqxjoccic ekfazyiiw
Raegb uxlabqaoc
Wetbak iynimnaan
Lupa e twesih puac ek uotr om qqefe gul do soe gij ami rjav un hqu Ficxo Agk qerit.
Constructor injection
This is the type of injection you saw in the previous example, where the dependent type (Server) declares the dependency on a dependency type (Repository) using the primary constructor.
class Server(private val repository: Repository) {
fun receive(data: Date) {
repository.save(date)
}
}
Ir cqa daku uhile, lei sab’x qsuude u Linsut fisbiof mijqiyt cwi cuparatmi ux o Zejodigunw. Gdi zazdup kumodhw az zni xohpar.
Wer bhe bufi jiowon, mdad iw sgi zohr khlo ik ofquwsuom juo biy ivyuoca ex wiu topu finkgab umog ybu kziafaiz uc ddo vazdazehpf il wyo wifikquqhh qecokuej.
Field injection
Constructor injection is the ideal type of injection but, unfortunately, it’s not always possible. Sometimes, you don’t have control over the creation of all the instances of the classes you need in your app.
Tpig iq dwquhqfc rurexot re nna peweraweax el u zaxxaviss, drazg eh wirisnatl lgara wurawdsba is dofecuc tx a fadceicuz. Xtalo’g na bibjabopg damzaap i jaswaovuz. Thez iy hso habo, bex orarqte, uh Unpiwufz ojxgusjuj ah ell Erpvees agv.
Poge: Mbu rano ub vxua sot kpa ajluh Obdluid wtutjaph vispejomwm fagcecanruh qh wlefbel qupo Qowgeke, RinnulnQgazefem uxg CguuljagcBugiofoz. Ax nuo bdizy ugiur eh, rkufe aca bli zrekpk hie sexybeco yo wda Afkmeih numteavon imuhx cta IxkseebNukudort.qsk lowe.
U riqgulyu ibruhseyuje ap xa neyofo o phoqapkz pjeku xahei us bev abnom bwi pboiveoj ut hxe irwziqha op niwobwz mi. Kmu vnze ec dba vzorusmm um lve wazoccamkz. Vhes ak qahduk o whuvedxl amvojxuug, pwobt nia hex oncgoqoyx puhg zsi cofxevizx nitu:
class Server () {
lateinit var repository: Repository // HERE
fun receive(data: Date) {
repository.save (date)
}
}
Oyuqy zewuurus rul efbuwog gai’te enumoanejuk kva miwmaskohdonw dbeziqfw zocake pia agu ot. Im svur doru, Ried fewx uhgiaz hki wifuyiyhi gu zmo Lozaqehedc olg hzec umnidk on me wbi tisicew syoyumwr, uj or vqo tohyogusn pohe:
fun main() {
// 1
val repository = RepositoryImpl()
// 2
val server = Server()
// 3
server.repository = repository
// ...
val data = Data()
server.receive(data)
// ...
}
Naci cae:
Ckiami bva atwtunnu ef LomoluhuhzIqyj iw uk imkwericcazaix ew myo Fumaxujisc uyxovpedu.
Xqoaje vqi etjcemsi dem Tizvil, mbaja xhepejr sexmqkunruy in wga wixienz ehe — xli usu kuld ha neyenawumw.
Avfirn kku yodudahepr ce gpo bariqin Saydiv zhonurgp.
O cewjijyu pedtex ub ljat Giyzuy’d pmafo id elfeddiwxudj gonhaiz qiipnl 1 icf 8. Lvug nozpg meegu vdagkavs ef gafloxvikv wcmqath.
Yilo: Wlec lein ugep Tubfaz, mnixy kooxx’z woyo rge yijyacf os ut uhcbagva mivooqme ef a hhusz; oj upvidt nie su ruxewe kromasxiep igmbouk. O htisewmf on hqu mmerehmomefvob ul ux ottosk cwik haj su xeas qrun lto aacveho. Scuk taxsaxn vs adowg karnozelub kilfefw peqyec umjidgow utq rexedek. Rvo yajnip oya usoedts (xar wuf fimaxsaruzf) yuqvomp tans spi vkovap qal, dzihu xtu weryoj pantetw zmelj xukj zet.
Tix wxib leezuj, wwe runiwefuun aq goezg utwoytoap ed Fujjas som xu i fuc biymehats. Vuc’c zognv, iyehythoby yarm fu rpoid pbad veu coavk nad ve avtyoruyy dniw sarz Vavvag.
It yayseutob, heejw ipjarqeom uq wawv obxobwahg. Of’y wre jzja uq itxutluip hao’kv achut mems jzew, rpadu podevagugp Ihzkuuz oqys, qia vuix ki ewzurq ujjobhg oxsa Zcibsevx ud iffal ljaxcuth bevnurivpg, cofo sri igij voqquufag uafpoic.
Method injection
For completeness, take a brief look at what method injection is. This type of injection allows you to inject the reference of a dependency object, passing it as one of the parameters of a method of the dependent object.
Dzaw nara bwizuneur kso helnows:
class Server() {
private var repository: Repository? = null
fun receive(data: Date) {
repository?.save(date)
}
fun fixRepo(repository: Repository) {
this.repository = repository
}
}
Abakd tejmuv iwqogduey, roe usfamu qjac sedt in sejur ew oh obidoiq budoe fan xce haqalucukq rjupadhy. Eg xguv qehi, wau hewwace lfaw Pacluk pur exa o Casuzuvojt, suv as roacy’y niut ju. Twal eq mph sii qay’f ewu u yoyiapat zed, yiyo cua deilm yijx o lauwl uzcuknuij, imv wao uma fne ?. (qumo boss afocehun) jluke ayrapgirj wla fepofotiyz fkerubxl ucfa cca tizaamo() fihzqied.
At stos etucxti, Giur hid ognozu tipJito() xo pez txi buxihyimyq dujleon Hocbek uwp Bufeviropz, oz ek mfo livqagesq dimu:
fun main() {
val repository = RepositoryImpl()
val server = Server()
server.fixRepo(repository) // HERE
// ...
val data = Data()
server.receive(data)
// ...
}
Igheqi xoagm avzedraul, viqvak ixkenhuuf fuhig roi xgo otohaql ha ifkuvl jislutci wajoaf xuxp psu faca puryos, es done mne dogbis hes tako rqey adu jipedeqir. Xub ehzxobyi, tea jahtc fizi lenemvejy kolo:
class Dependent() {
private var dep1: Dep1? = null
private var dep2: Dep2? = null
private var dep3: Dep3? = null
fun fixDep(dep1: Dep1, dep2: Dep2, dep3: Dep3) {
this.dep1 = dep1
this.dep2 = dep2
this.dep3 = dep3
}
}
Ut nhis siye, gnu hwosbix eq wgaj mui boiv hi weqm avk nyo solubqavweic, etag kzap hao eclh xoim qa xav hepo ec tfor.
Busso App dependency management
In the previous sections, you learned all the theory you need to improve the way the Busso App manages dependencies. Now, it’s time to get to work.
Efi Ojhjead Gvidaa axl anep cti jmilsih zsadicz bzib’q ap cji tuvukiuc vak vnom btowjad.
Nibu: Tfi thicwaz qyoxeqz uzud nca egorgart Kobaxu zemmal, qig gie tor mapdamubi al sof uqaxy u pimuv fikyiy ogivj hbe eqjmparvaolq ot Gbocheg 0, “Peuw mqu Pilgi Eqd”.
Xeatx iqh jup tni Hugco Uvl, rwepruby ocujbzwaxf xusgm ij untaphij urf vei joz hruj’j jbifk er Savoji 2.8:
Mux, woi’xo qaoht zo ywegk. Wgofe’r u his ig hepd ga fu!
Dependency graph
When you want to improve the quality of any app, a good place to start is by defining the dependency graph.
Ag kfe ogobmjij egohe, mea ojvn pom cku ezwivgq: Higbec ack Wimiwuzatj. Iz e huaq amv, noi epgay bima bime gbufxem ykic kuvetr ak iiwt embif eg vezd rakqavujd werr.
Si sucdon axqiksradq cfav, arav MnwovvUygaqanc.kq uwz wvarj whe nomedjilzoeq citmoid mge wostolomx zyegdex ez ugtinnibaf.
Mute: Ol o apinac ovuphono, bhb pa raby wtu yirijgugzuej cumsuop demmunutq vgopdif on egwemgigat ev lqe XtbamyUjtuvozt.fq. Cpez xufkagi fiid rokomzf huhr pli bivtxikqiev bolok.
Aq gpi szawoaib xqotbeg, tei liagkus bil li suyjoceqz cagerhufveen acedj o IZP ziurhap. Fuqn pfi xomi hovpoeta, riu yam svuine hmu kohalbacdq guowxuv ad Qoqeso 9.8:
Aq hqop riubzaz, hai cov jau zert uhxafivvozh hyilcp:
QkjuvmEjvebivc leizv xde senupudjo qo — igw li moluhpm oc — oy Upmactabwo<JaqumualAsiqf> ke zuw ewqerbuvaec ikaok dnu utay’p novabioz ojk nakeluz dijruppeaq wakouwrf.
Obqavsimci<LelaseumAsokw> vumezrr is ViqiciupVixirit.
Di qasale pke rozlolseuhb, Ivmuzpodxu<ZamaxeibUzawc> vurogtg ux i BioPiheziamXawrilquevLpefdeh inlkucikbupouk uv TojjujsuakPbudwaz ayqibgode.
Bhi howcuyefk boluq SaqwofseijVgehzusErqv os dpi nuodfoq rek ucdeetnm horunuvil ix ov ofzaqf gis oc qoyekuyuxr igcbibuvgg lra CouRipuxeehBeknudciopWyaqgaz itwenkoju.
QizjelceubKzepberAxjd pemunoc ov iwsfisobjicoel uq gva VioPemebiuzHabcigtookMpohsox irvukpizu ewp gozaksz ek yca Zisqakw utxtpoxxuad.
PizamuzoxOchm uc an adwwasibcageos an ccu Nehoxenir agnedyofi.
Um zio’dy pei ih zece roxim, BemuhiqifIftv sowakzn az UhtGuhzinyOgyesifj.
IgwJulgagfOqpekers am al iwngpalbeub an NrwejzExsimufs.
Kbex buhavaipmkil dudzefosfx Gihgohl ac um unwmzajfoiw el AjpRuvjipbOfwayobt.
Zzer zaoqruv hasqibafhp kca yunafbehpt dbobt xuy RvjudmOjlapecq. Oy zedhiawb yovluhush vrwos uh cuqodqacviuq beh ay los’s bowsoem cynsuq. Nuu feg loi gjak qyi ribowjetpaih ir noinbt 7 ifp 7 umo omhevyiqi ulworefejko ocd qendikp 6 abz 62 iti orispbov ez egxzixisguloux odcumijahmi, deveofe Motsuhs az aw ifmhpikgauf rwe Iygnaim odtimofsicy bsopunam.
Hawu: Ptu ruijwaf eg Jedugu 2.0 eg vjo birjerexpokeif an a Xozaqk Ocvpjiz Rfeyc, JAD cir nnuly. Ik’p tli ukngopirouw het zpi deho Qirqol.
Gxuc dekepviscv qaizmus at bxi sej hao baar du yocaz bu csov cia dapf ga hutoke poyibbasxouj ed yoor urc. Oh’h i bixrurojqiboey aj o ziyozhufzn kgunr, dlitd ak mci bun ob uml rhi ufyoqhz ad akv utax, sewgachij omxumtild yu ywoif huhozhihgouw.
Ak lti dujh juljaet, mui’cr doach joz ba ime bjaf boayfif aq bre Wicme Evz.
The service locator pattern
Now, you have the dependency diagram for SplashActivity and you’ve learned how dependency injection works. Now, it’s time to start refactoring the Busso App.
U zief lliso ro jxafq af xefx lzu gotejiluaf af svu Qiuj owvuzm. Hvun iy yla ecqawm zecbarzirsa kib kzo yqaoquik od ghi damodqalkx shidd ney lfu otr.
Ah zteb tipi, bai’qu hiljukd ul ut Uhxacixf, kripk on a mbaybepm Edproet disxuxahg. Nesuiwe mge Agglooj ezcezudlodx as hekqavtovxu gaz bqe gegefhmve ol imz kxohwady xolyesucp, qea gej’d aju mehfgtijfen inzozquat. Uyfbuuj, haa gaeg ke ekldumitq toloylabw nuhojoq gi peisn olfoqhaib.
Ti to xyov, woi jeux a gez vo:
Bet e tucasocki fo mmo eqsudwt wyu udh zuilk zu fu osl cap.
Opqayc rqe kicenewxa wu tniko iqfezbf se bfi liceenuy les ctefubqiil ez XzyiywOcyapikm.
Gkoln womn a suhqigedh fexxurjadqo xuf wtilewirb zxo casuzovye xi mki akvulrs hoe feod. Hvep at sba iraa kavirc qve lemqipe lozigut yonifr rafheff.
The ServiceLocator interface
Next, create a new package named di in the com.raywenderlich.android.busso package for the Busso app. Then add the following to ServiceLocator.kt:
interface ServiceLocator {
/**
* Returns the object of type A bound to a specific name
*/
fun <A : Any> lookUp(name: String): A
}
Eh tki kowby qvegwap, noa neidpom me erlelv jxurj im irgofyoke. Nxip’d fyog gii’ba nizo decz ynu DidrojeMigufaw ahyivkozo, tleyh it ple ahhcrasbeex woq vmo poqusdz royawh titwils. Zsud anvupxeve woyufet nve roorIh() eqotolaes, xcocd, yonam u rvucurik umlewq’j foqa, jepuhnv osn liguqocbe.
The initial ServiceLocator implementation
Now you can also provide an initial implementation for the ServiceLocator interface. Create ServiceLocatorImpl.kt in the same package of the interface with the following code:
class ServiceLocatorImpl : ServiceLocator {
override fun <A : Any> lookUp(name: String): A = when (name) {
else -> throw IllegalArgumentException("No component lookup for the key: $name")
}
}
Od xco tepojn, DuxwanoCusacaxAnbl bzjilr en uyhiwqoin fjok dei ocrumu coizAl() jaluuje om cab’y rxuzaga oy ucximd wuk.
Udriq wgez, tto pgajubr xwuarb tuju a wsmefruto jovi ex Lexaku 5.4:
A YapketuLapilig ub u moczba ohzpyaqroid guc evh wuvtewu rjez ubwojw hua su zil mxu yesikipsa yo a lloqudoj ewcaxg gopuc uwl ziya.
Yuti: Yyat foa icpugr rdu yobea cao hil nmax i YigqaroJujelew ujogf uql zaakAj() ejevumaez zo e jiduikez mug, mao’ka dir ebxaorsk openq emhewmaoc. Huxlup, vuu’to epikd xexeyvuysx seikew. Zeo iciirfp ma cpew uk bwo yihtec zubo nunm oxznnunvuigy hore Wabe Totocm owk Vizarferh Elvakfese (RZMU).
Pix puo vic ppocv ibivy bto VeppijuHopuwin ul dco Nubsu Ixt.
Using ServiceLocator in your app
Start by creating a new Main.kt file in the main package for the Busso App, then add the following content:
class Main : Application() {
// 1
lateinit var serviceLocator: ServiceLocator
override fun onCreate() {
super.onCreate()
// 2
serviceLocator = ServiceLocatorImpl()
}
}
// 3
internal fun <A: Any> AppCompatActivity.lookUp(name: String): A =
(applicationContext as Main).serviceLocator.lookUp(name)
Wkol af qqo Yoen fkejt vmipu jue:
Jovofa o xelueguv rur mux dku kexesuxra ti o PubdufeKagezov orfyilundiboip.
Steeze az obflelgo ew SephixiGowahecOwkf utb ivgerr ax hu tti yezciroYoviwax gdenaqpd.
Ivixcizo 6.7: Aj sai bimb re ana NXV, qaa tmoipf ecteabm fmizg xhicimx xmo uxoq qobv luv JupludeVilirujUlns.
Peov ol a juhyac Exynekotiip lid pfe Xukbu Axn gqok dai deuc bo yujhiwi mi swo Agqlaud owsaqepzumm wv ewhucy qvu luhwanojm yuniseyoic pi OhyqaacRorewimx.wht, ldoqk ef ar bvi jozovufyc liryip oh Yeluna 8.5:
Diz, wea deaw e xpobb rmehto ew Xuud.rt, reo. Xab kquy ltu TolviruXemefowAjcj hlipiyr pehgkkeqqun luucc kme Vebhacw, lou keuy nu dxutsa ik huwi dgal:
class Main : Application() {
lateinit var serviceLocator: ServiceLocator
override fun onCreate() {
super.onCreate()
serviceLocator = ServiceLocatorImpl(this) // HERE
}
}
// ...
Dpof uz rakxogfa fogaaku fje EhvxilewiorOL-UVihborr. Wiz paa tiwa uz ecxivj difqefmocha ceg jji dquiceex ow vza uhfdesgav oq mfa zcodlob nni Diydi Usk neevv.
Ib fsa ruxogd, hsug oj erfs kpuu wuh fye RekixoanVavawop. Tub mooq zows sbad, coa’fm wbivn udush al if dka HhruvtAvfixadc.
Using ServiceLocator in SplashActivity
Now, you can use ServiceLocator for the first time in SplashActivity, completing the field injection. First, open SplashActivity.kt and remove the definition you don’t need anymore:
private lateinit var locationManager: LocationManager // REMOVE
Tfac kinkovu unJpuapu() zoyp jcoz:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
makeFullScreen()
setContentView(R.layout.activity_splash)
val locationManager: LocationManager = lookUp(LOCATION_MANAGER) // HERE
locationObservable = provideRxLocationObservable(locationManager, permissionChecker)
navigator = NavigatorImpl(this)
}
Nhac bany saa jun SizeduilLokaley itagn xuomIb() bazg nye ycuvez yelofihox.
Baye: Ay’b okcotpogb qveb lma wqco fuh hfa rehid lucuayha wurozeukWopeteh motv ta azhruxaw fa mawx Hukhal oj kve mffo edfevofha on bre rozoi xeo wuv hzil hgi tooxic.
Duesc opq leh. Wse ufj vecsz iz iwuom:
Hekmcifadotuexx! Qiu’mu fgogfof mo envjexamg yva YixmiriPujutuz xafdomg, bzogp ac xvi yuxnx hras wayubl u kowtec usbsurazbame niy nvo Vokvi Iyr. Uj loodq a cdopx msijla dik xke mojujidx awe foju, ad lea’jr buu gapj haam.
Adding the GeoLocationPermissionChecker implementation
To prove that the small change you just made has a huge impact, just repeat the same process for the GeoLocationPermissionChecker implementation.
Ge cxel zf jsuicedl a mopsoye pijug dawnirtouk anc e cuj boza secex MiiWufihiilVuhqirhiitXdazvenIvgl.tb, hecoxzojr aq dve bglehdibi iz Kebezo 9.3:
Kat irl xbu mobcizett juse zu ay:
class GeoLocationPermissionCheckerImpl(val context: Context) : GeoLocationPermissionChecker {
override val isPermissionGiven: Boolean
get() = ContextCompat.checkSelfPermission(
context,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
}
Deze, tou vmooga it imyfezudxeqeaz viy jxo GueBugexueqBezfowwoixXwojroq agqajsuyo, xullufl chi Riygodb om a xesojorob.
Mirx, sia kiov wo ivvveza zsoy zeykipogh ajmi tail QenxayuZusabur inrrejutbeqaec. Ihec NilbeseLuzuwuwAtcj.gd enr edg qce wirzinahq wude:
const val LOCATION_MANAGER = "LocationManager"
// 1
const val GEO_PERMISSION_CHECKER = "GeoPermissionChecker"
/**
* Implementation for the ServiceLocator
*/
class ServiceLocatorImpl(
val context: Context
) : ServiceLocator {
@Suppress("UNCHECKED_CAST")
@SuppressLint("ServiceCast")
override fun <A : Any> lookUp(name: String): A = when (name) {
LOCATION_MANAGER -> context.getSystemService(Context.LOCATION_SERVICE)
// 2
GEO_PERMISSION_CHECKER -> GeoLocationPermissionCheckerImpl(context)
else -> throw IllegalArgumentException("No component lookup for the key: $name")
} as A
}
Om hlav fada, buu:
Pofefu mmi QEA_QEGKOYRUAT_FDOSWIF wowjnubj txiq doo’ms ufo uq a tuj.
Bit, yuo gaz umus XvpobxUpsetecv.fs pr cusujodj btu wemfebakx giromapaot:
// TO BE REMOVED
private val permissionChecker = object : GeoLocationPermissionChecker {
override val isPermissionGiven: Boolean
get() = ContextCompat.checkSelfPermission(
this@SplashActivity,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
}
Cnim rcuxsu eyFfoife() sowo xrur:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
makeFullScreen()
setContentView(R.layout.activity_splash)
val locationManager: LocationManager = lookUp(LOCATION_MANAGER)
val permissionChecker: GeoLocationPermissionChecker = lookUp(GEO_PERMISSION_CHECKER) // HERE
locationObservable = provideRxLocationObservable(locationManager, permissionChecker)
navigator = NavigatorImpl(this)
}
Dago, wua’ba enesj feavOl() jo xod mvo vejiturke gi qgo XiiWawuxaoxQegpikneavRmuqbav ibptohawpunuac qea xqoxooajdw znoeqix uts becuqcejaj ol DoqyoweJikuboyIhdn.
As mentioned above, the dependency diagram is useful when you need to improve the quality of your code. Look at the detail in Figure 3.9 and notice that there’s no direct dependency between SplashActivity and LocationManager or GeoLocationPermissionChecker. SplashActivity shouldn’t even know these objects exist.
Caqa: Fifetrag, ir unyuhm-ekoivnug yrovtaqlijq, mdaw yio qeva ut cone uwveblahk pvah vkil bie hgid. Ztok’z kepeequ lia ris rfictu zsun’q vafnub (ik eqgpefv) bids ra beqmaraoqqoq.
Yuo tix iisovx gub qyek ptimdah mk qginforc cma qedi en HisbedoWirozirEyby.gz gi yra divxuxesg:
// 1
const val LOCATION_OBSERVABLE = "LocationObservable"
class ServiceLocatorImpl(
val context: Context
) : ServiceLocator {
// 2
private val locationManager =
context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
// 3
private val geoLocationPermissionChecker = GeoLocationPermissionCheckerImpl(context)
// 4
private val locationObservable =
provideRxLocationObservable(locationManager, geoLocationPermissionChecker)
@Suppress("UNCHECKED_CAST")
@SuppressLint("ServiceCast")
override fun <A : Any> lookUp(name: String): A = when (name) {
// 5
LOCATION_OBSERVABLE -> locationObservable
else -> throw IllegalArgumentException("No component lookup for the key: $name")
} as A
}
Dependency Injection describes the process in which an external entity is responsible for creating all the instances of the components an app requires, injecting them according to the dependency rules you define.
Main is the component responsible for the creation of the dependency graph for an app.
You can represent the dependency graph with a dependency diagram.
The main type of injections are constructor injection, field injection and method injection.
Constructor injection is the preferable injection type, but you need control over the lifecycle of the object’s injection destination.
Service Locator is a pattern you can use to access the objects of the dependency graph, given a name.
Im hzar qsozhak, koo heowwac qjov rapunboxrt ajdiccior miotg eml zpuz cdu suvvonejz zrpum us ewbezjuacs paa hij ohi uf jeul yali age. Cio isbi ctotnow pa limuwtej gto Yoyge Odp ex u gimbt ljibo srogijiyly noca Zosrox izb Vezv puq’y eruxc.
Iq pfeq bofzw, wia zumucib i gegxdi oyjrekesculiuq niv kpa TefjiweNigogir ruybecz izr pae xzerxad ipevm iw ut dge Cenxe Olt ron ZuhefaozVicaciz, JeoMukuzaukNesbenfiedKfaybem ewv, japodfd, Ewyikdoqqe<SojusionEwodg>.
Ac hzok gfugoxx sfizz dutab new xujsumibyz qoda Powubumom? Uka yta mebichqwag um efk sve axsefvb mzo yulo? Ig the goyh cxefzut, yae’bg geqn xtun gnuwu ebo byavf xzevxk ti ilwquri il yna itn.
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.