Kung papasok ka pa lang sa mundo ng Android, tiyak na naranasan mo na ang walang-katapusang problema kung paano pangasiwaan ang data sa presentation layer. Sa loob ng mahabang panahon, nangingibabaw ang LiveData, ngunit sa pagdating ng mga Kotlin coroutine, lumitaw ang mas makapangyarihan at flexible na mga tool. Pinag-uusapan natin ang StateFlow at SharedFlow , na siyang natural na ebolusyon para sa pamamahala ng mga daloy ng data nang reaktibo at mahusay.
Ang totoo, kahit na sa unang tingin ay magkatulad ang mga konsepto, bawat isa ay may kanya-kanyang layunin. Ang pagnanais na maalala ng screen kung saan natapos ang news feed ay hindi katulad ng pagnanais na magpadala ng mabilis na notification para sa isang Toast na dapat lamang matingnan nang isang beses. Upang maiwasan ang kalituhan, ating suriin kung paano gumagana ang mga hot stream na ito at kung bakit dapat mong isaalang-alang ang pag-iwan sa LiveData sa iyong mga modernong proyekto.
Ang konsepto ng Daloy: Malamig o Mainit?
Para maunawaan ang StateFlow at SharedFlow, kailangan mo munang maunawaan ang pagkakaiba ng cold at hot flow. Ang standard flow ay cold , ibig sabihin, parang recipe ito: walang mangyayari hangga't walang magdesisyon na isagawa ito (tawagin itong 'collect'). Ang problema ay kung mayroon kang tatlong subscriber, ang code ng producer ay tatlong beses na ipapatupad, na maaaring makaubos ng baterya o makagawa ng mga paulit-ulit na API request.
Dito pumapasok ang mga hot stream. Parehong madiskarteng mainit ang StateFlow at SharedFlow , ibig sabihin ay nananatiling aktibo ang producer kahit may nakikinig o hindi. Pinapayagan nito ang maraming kolektor na ibahagi ang parehong pinagmumulan ng data , na pumipigil sa app na paulit-ulit na gawin ang parehong trabaho—mahalaga para mapanatili ang pagkalikido ng system.
StateFlow: Ang mainam na kapalit para sa LiveData
Ang StateFlow ay mahalagang isang state container. Ang pangunahing tampok nito ay palagi nitong pinapanatili ang kasalukuyang halaga , na maaaring i-query nang sabay-sabay gamit ang .value property. Ito ang perpektong tool para sa pamamahala ng estado ng user interface, tulad ng kung naglo-load ang isang screen o kung matagumpay na na-update ang data ng profile.
Hindi tulad ng LiveData, ang StateFlow ay nangangailangan ng isang paunang halaga sa constructor nito, na nag-aalis ng kawalan ng katiyakan ng pagkakaroon ng mga null states sa startup. Bukod pa rito, ipinapatupad nito ang conflation at deduplication behavior : kung ilalabas mo ang parehong halaga nang dalawang beses nang magkakasunod, babalewalain lang ito ng flow. Mahusay ito para maiwasan ang UI na mag-refresh nang hindi kinakailangan kahit na ang data ay hindi naman talaga nagbago.
Para maipatupad ito sa isang ViewModel, ang pinakamahusay na paraan ay ang paggamit ng isang pribadong MutableStateFlow fallback property at ilantad ito bilang isang immutable StateFlow. Tinitiyak nito na tanging ang ViewModel lamang ang makakapagbago ng estado, na nirerespeto ang unidirectional data flow at pinipigilan ang view sa pagmamanipula ng data.
SharedFlow: Ang bus ng kaganapan para sa mga natatanging aksyon
Kung ang StateFlow ay para sa "state," ang SharedFlow naman ay para sa "events." Isipin mong gusto mong magpakita ng error dialog o mag-navigate sa ibang screen. Kung gagamit ka ng StateFlow, ang pag-ikot ng device ay magiging sanhi upang matanggap ng bagong collector ang huling value, at muling gagana ang event —isang malubhang bug. Nalulutas ito ng SharedFlow dahil maaari itong i-configure gamit ang replay value na zero.
Ang daloy na ito ay mas nababaluktot at nagbibigay-daan sa atin na isaayos ang mga parameter tulad ng overflow buffer . Kung mapuno ang buffer, maaari nating piliing suspindihin ang nagpadala o itapon ang pinakaluma o pinakabagong halaga. Ang isang pangunahing bentahe ay pinapayagan ka ng SharedFlow na magpadala ng mga paulit-ulit na halaga ; kung kailangan mong ipadala ang parehong mensaheng "Connection Error" nang tatlong beses, gagawin ito ng SharedFlow nang walang pag-aalinlangan, samantalang sinasala ito ng StateFlow.
Teknikal na paghahambing: StateFlow vs SharedFlow vs LiveData
Para maiwasan ang kalituhan sa isang teknikal na panayam o kapag nagdidisenyo ng iyong arkitektura, mahalagang isaalang-alang ang mga kritikal na punto. Simple lang ang LiveData at awtomatikong pinamamahalaan ang lifecycle , ngunit lubos itong nakatali sa Android. Ang StateFlow at SharedFlow, bilang bahagi ng Kotlin Coroutines, ay platform-independent , na lubos na nagpapadali sa unit testing at sa paglikha ng mga malinis na domain layer.
- StateFlow: Pinipilit ang isang paunang halaga, may .value, inaalis ang mga duplikado na halaga, at mainam para sa mga estado ng UI.
- SharedFlowHindi ito nangangailangan ng paunang halaga, maaaring i-configure sa mga tuntunin ng pag-replay, at ito ang tamang opsyon para sa mga panandaliang kaganapan.
- LiveDataHindi ito nangangailangan ng paunang halaga, alam nito ang siklo ng buhay ngunit hindi gaanong makapangyarihan sa mga asynchronous na pagbabago.
Ang kahalagahan ng ligtas na pag-aani
Isang karaniwang pagkakamali ang pagsasagawa ng isang `collect` sa loob ng isang simpleng coroutine scope sa Activity. Mapanganib ito dahil ang flow ay magpapatuloy sa pagproseso ng data kahit na nasa background ang app , na maaaring magdulot ng mga pag-crash o labis na paggamit ng CPU. Ang modernong solusyon ay ang paggamit ng `repeatOnLifecycle(Lifecycle.State.STARTED)` API.
Ang function na ito ay nagiging sanhi ng pag-activate ng collection kapag nakikita ang view at awtomatikong magkakansela kapag naabot nito ang STOPPED state . Para sa Jetpack Compose, ang rekomendasyon ay gamitin ang `collectAsStateWithLifecycle()` , na siyang natural na nagsasama ng logic na ito at tinitiyak na ang application ay mahusay sa paggamit ng mga resources ng device.
Pagbabago ng malamig na daloy tungo sa mainit na daloy
Minsan mayroon tayong daloy na nagmumula sa isang database (tulad ng Room) o isang repository, at ito ay malamig. Para gawin itong mainit, ginagamit natin ang mga operator na `stateIn` o `shareIn` . Ang mga operator na ito ay nangangailangan ng `CoroutineScope` at isang startup strategy. Ang pinakakaraniwan ay ang `SharingStarted.WhileSubscribed(5000)`.
Napakahusay ng configuration na ito dahil pinapanatili nitong aktibo ang stream hangga't may mga subscriber, at kung nakasara ang screen, naghihintay ito ng 5 segundo bago ihinto ang stream. Mahalaga ito upang, habang umiikot ang screen , hindi masira at muling mabuo ang stream, kaya maiiwasan ang mga hindi kinakailangang request sa server o sa lokal na database.
Ang pagiging dalubhasa sa mga tool na ito ay nangangailangan ng pag-unawa na ang estado ay dapat na persistent at deduplicated gamit ang StateFlow, habang ang mga minsanang aksyon ay dapat dumaloy sa SharedFlow. Sa pamamagitan ng pagsasama nito sa kamalayan sa lifecycle at cold flow transformation gamit ang stateIn, nakakamit natin ang isang matatag at ganap na reactive na arkitektura ng Android na na-optimize para sa totoong pagganap sa mga mobile device. Ibahagi ang gabay na ito at tulungan ang iba na matuto tungkol sa paksang ito.
