Kung naramdaman mo na parang nagiging gulo na ang code ng iyong Android app, dahil parang mainit na patatas ang mga instance na pinapasa mula sa isang class patungo sa isa pa, malamang na nahulog ka na sa bitag ng... impyerno ng mga dependencyPara maiwasan ang pagiging mahirap pamahalaan ng iyong proyekto, ipinakilala ng Google ang Dagger Hilt, isang tool na humahawak sa lahat ng mabibigat na gawain, na awtomatiko ang paghahatid ng mga bagay na kailangan ng iyong mga klase nang hindi mo na kailangang isulat ang parehong code nang paulit-ulit hanggang sa magsawa ka na.
Hindi tulad ng kumbensyonal na Dagger, na kung minsan ay maaaring nakakatakot dahil sa matarik na kurba ng pagkatuto nito, ang Hilt ay nag-aalok ng mas estandardisado at direktang pamamaraan. Gumagana ito nang mahusay sa Jetpack Compose at mga modernong arkitektura, ino-optimize ang runtime performance at tinitiyak na hindi ka makakaranas ng mga hindi kanais-nais na sorpresa dahil sa mga nawawalang dependency error, dahil lahat ay napapatunayan habang nagko-compile.
Paunang pag-configure at pagsisimula ng system
Para simulan ang paggamit ng Hilt, ang unang hakbang ay ang pag-set up ng environment sa iyong mga Gradle file. Mahalagang idagdag ang hilt-android-gradle-plugin sa root file at pagkatapos ay ilapat ang mga dependency sa iyong application module. Ang isang mahalagang punto rito ay dapat na naka-configure ang proyekto upang Java 17Kung hindi, ang mga kasalukuyang bersyon ng Hilt at Compose ay maaaring magbigay sa iyo ng ilang sakit ng ulo.
Para magsimulang gumana ang mahika, ang anumang app na gustong gumamit ng sistemang ito ay dapat mayroong klase ng Application na minarkahan ng anotasyon @HiltAndroidAppAng label na ito ang switch na nagpapagana ng code generation at lumilikha ng base kung saan ilalagay ang buong object graph; kung wala ito, walang mapaglalagyan ang Hilt at wala kang gagawing kahit ano.
Paglalagay ng mga dependency sa mga bahagi ng Android
Kapag na-set up na ang base, kailangan nating sabihin sa Hilt kung saang mga klase natin gustong matanggap ang mga object. Para gawin ito, ginagamit natin ang @AndroidEntryPointTugma ito sa karamihan ng bahagi ng framework, tulad ng Activities, Services, at BroadcastReceivers. Kung gumagamit ka ng Compose, lagyan lang ng anotasyon ang root Activity, at lahat ng composable element ay makaka-access sa injected ViewModels nang walang anumang problema.
Para direktang magpasok ng isang object sa code ng isang activity, ginagamit natin ang field injection na may @InjeksyonKailangan mo lang tukuyin ang variable bilang `lateinit var` at idagdag ang anotasyon. Gayunpaman, maging maingat: ang mga injected field ay hindi sila maaaring maging pribadodahil kailangan ng Hilt ng access sa mga ito para ilaan ang instance; kung susubukan mong gawing pribado ang mga ito, agad kang bibigyan ng compiler ng error.
Ang sining ng pag-uugnay: @Binds laban sa @Provides
Kailangang malaman ng Hilt kung paano gawin ang lahat ng hinihiling natin dito. Ang pinakasimpleng paraan ay ang constructor injection, kung saan nilalagay natin ang anotasyon sa class constructor gamit ang `@Inject`. Ngunit may mga pagkakataon kung saan imposible ito, tulad ng kapag ginagamit ang mga panlabas na interface o library Retrofit o Uri ng Kwarto, kung saan hindi natin maaaring hawakan ang source code para magdagdag ng mga anotasyon.
Dito pumapasok ang mga module, na mga klaseng may anotasyon ng @Module at @InstallIn. Kung gusto nating i-link ang isang interface sa isang konkretong implementasyon, ang pinakaepektibong paraan ay ang paggamit ng @BindsAng isang abstract function ay tinukoy kung saan ang parameter ay ang implementasyon at ang return ay ang interface; ito ay karaniwang nagsasabi sa Hilt: "kapag ang isang tao ay nangangailangan ng AnalyticsService, bigyan sila ng AnalyticsServiceImpl".
Sa kabilang banda, kapag ang paglikha ng bagay ay nangangailangan ng mas kumplikadong lohika o nagmumula sa isang ikatlong partido, ginagamit natin @NagbibigayDito, nagsusulat tayo ng isang normal na function kung saan ang katawan ay detalyadong nagdedetalye kung paano eksaktong binubuo ang instance, tulad ng kapag kino-configure ang base URL ng isang Retrofit client. Sa madaling salita, habang ang @Binds ay ginagamit para sa delegasyon, ang @Provides ay ginagamit para sa manu-manong lumikha ng dependency.
Pamamahala ng tunggalian gamit ang @Qualifier
Minsan kailangan natin ng dalawang magkaibang bersyon ng parehong uri ng object. Isipin na mayroon kang dalawang OkHttpClient client: isa para sa mga tawag na nangangailangan ng authentication at isa pa para sa mga pampublikong kahilingan. Kung susubukan nating i-inject ang pareho nang walang karagdagang configuration, mag-panic ang Hilt dahil hindi nito malalaman kung alin ang pipiliin. Upang malutas ang problemang ito, ginagamit natin... mga pasadyang kwalipikasyon.
Ang isang qualifier ay karaniwang isang self-anotation na minarkahan ng @KwalipikadoGumagawa tayo ng mga tag tulad ng @AuthInterceptorOkHttpClient at inilalagay ang mga ito sa method ng module na nagbibigay ng instance at kung saan natin ito ini-inject. Sa ganitong paraan, maaaring pag-iba-ibahin ng Hilt ang mga binding na may parehong uri nang walang mga error. Bukod pa rito, may mga kapaki-pakinabang na pre-built qualifier tulad ng @ApplicationContext at @ActivityContextna siyang nagliligtas sa atin mula sa paggawa ng sarili nating mga modyul upang makuha ang Konteksto ng Android.
Pag-synchronize ng mga siklo ng buhay at scoping
Bilang default, lumilikha ang Hilt ng bagong instance sa bawat oras na humiling ng dependency. Gayunpaman, may mga sitwasyon kung saan gusto nating manatiling pareho ang object sa buong lifespan ng component. Para dito, mayroon tayong... mga saklawKung mamarkahan natin ang isang klase gamit ang @Singleton at i-install ito sa SingletonComponent, magkakaroon tayo ng isang instance na ibinahagi sa buong aplikasyon.
Mayroon ding mas tiyak na mga antas. Halimbawa, @ActivityScoped Tinitiyak ng `@ViewModelScoped` na ang parehong instance ay ginagamit sa buong buhay ng isang aktibidad, habang ginagawa rin ito ng `@ViewModelScoped` para sa ViewModel, na pumipigil sa muling paggawa ng dependency kapag inikot ang screen. Gayunpaman, hindi ipinapayong labis na gamitin ang mga scope, dahil ang pag-iingat ng mga object sa memorya nang masyadong matagal ay maaaring humantong sa mga problema. makapinsala sa pagganap at pamamahala ng memorya ng Android.
Mga espesyal na kaso: @EntryPoint at mga hindi sinusuportahang klase
Napakalakas ng Hilt, ngunit hindi nito naaabot ang lahat. May mga klase ng sistema, tulad ng ContentProvider, na hindi sumusuporta sa @AndroidEntryPoint. Sa mga sitwasyong ito, ang solusyon ay ang paglikha ng entry point gamit ang @EntryPointTinutukoy nito ang isang interface na nagsisilbing tulay sa pagitan ng code na pinamamahalaan ng Hilt at ng external code.
Para mabawi ang mga pasilidad mula sa tulay na ito, ginamit namin ang Mga Accessory ng EntryPointIpinapasa natin ito sa naaangkop na konteksto at sa interface ng EntryPoint, na nagbibigay-daan sa atin na manu-manong kumuha ng mga dependency mula sa Hilt graph kahit sa mga sulok na hindi maabot ng awtomatikong pag-iniksyon.
Mga Pagkakaiba sa pagitan ng Hilt at Dagger
Ang Hilt ay hindi kapalit ng Dagger, kundi binuo batay dito. Ang pangunahing bentahe nito ay inaalis nito ang pangangailangang manu-manong isulat ang mga bahagi at pamahalaan ang kanilang mga lifecycle, dahil Awtomatiko itong bumubuo ng mga lalagyan naka-link sa mga klase ng Android. Malaki ang nababawasan nito sa paulit-ulit na code at ginagawang mas madaling basahin ang proyekto.
Ang sistemang ito ay nagpapahintulot sa inversion of control na maging isang natural na proseso: sasabihin sa iyo ng mga klase kung ano ang kailangan nila, at ang Hilt ang bahala sa pagbibigay nito. Hindi lamang nito pinapasimple ang pang-araw-araw na pag-unlad kundi isa ring biyaya para sa mga pagsubok sa yunitdahil maaari nating palitan ang mga aktwal na implementasyon ng mga test double nang hindi kinakailangang hawakan ang business logic.
Ang implementasyon ng Hilt sa Android ay nagbibigay-daan sa matatag at mahusay na pamamahala ng dependency, inaalis ang paulit-ulit na code at pinapadali ang paglikha ng mga scalable na application. Salamat sa tumpak na paggamit ng @Binds, @Provides at @QualifierMaaaring lutasin ng mga developer ang mga conflict sa uri at pamahalaan ang lifecycle ng object sa isang detalyadong paraan, na tinitiyak na ang application ay napapanatili at madaling subukan sa pamamagitan ng inversion of control.