Hvis du er nybegynner i Android-verdenen, har du sikkert møtt det evige dilemmaet med hvordan man håndterer data i presentasjonslaget. I lang tid var LiveData det viktigste, men med ankomsten av Kotlin-rutiner har det dukket opp mye kraftigere og mer fleksible verktøy. Vi snakker om StateFlow og SharedFlow , som i hovedsak er den naturlige utviklingen for å håndtere dataflyter reaktivt og effektivt.
Sannheten er at selv om de i utgangspunktet kan virke som lignende konsepter, har hver sin hensikt. Å ønske at skjermen skal huske hvor nyhetsfeeden slapp er ikke det samme som å ønske å sende et raskt varsel for en Toast som bare skal vises én gang. For å unngå forvirring, la oss se på hvordan disse aktive strømmene fungerer og hvorfor du bør vurdere å utelate LiveData i dine moderne prosjekter.
Konseptet flyt: Kaldt eller varmt?
For å forstå StateFlow og SharedFlow må du først forstå forskjellen mellom en kald og en varm flyt. En standardflyt er kald , som betyr at den er som en oppskrift: ingenting skjer før noen bestemmer seg for å kjøre den (kall «collect»). Problemet er at hvis du har tre abonnenter, kjøres produsentens kode tre ganger, noe som kan tappe batteriet eller gjøre API-forespørsler overflødige.
Det er her «hot streams» kommer inn i bildet. Både StateFlow og SharedFlow er strategisk «hot streams» , noe som betyr at produsenten forblir aktiv uavhengig av om noen lytter. Dette lar flere samlere dele den samme datakilden , noe som forhindrer at appen gjør det samme arbeidet gjentatte ganger – viktig for å opprettholde systemets flyt.
StateFlow: Den ideelle erstatningen for LiveData
StateFlow er i hovedsak en tilstandsbeholder. Hovedfunksjonen er at den alltid opprettholder en gjeldende verdi , som kan spørres synkront ved hjelp av .value-egenskapen. Det er det perfekte verktøyet for å administrere tilstanden til brukergrensesnittet, for eksempel om en skjerm lastes inn eller om profildataene er oppdatert.
I motsetning til LiveData krever StateFlow en startverdi i konstruktøren, noe som eliminerer usikkerheten ved å ha nulltilstander ved oppstart. Videre implementerer den sammensmeltings- og dedupliseringsatferd : hvis du sender ut den samme verdien to ganger på rad, ignorerer flyten den ganske enkelt. Dette er flott for å forhindre at brukergrensesnittet oppdateres unødvendig når dataene faktisk ikke har endret seg.
For å implementere dette i en ViewModel er den beste tilnærmingen å bruke en privat MutableStateFlow-fallback-egenskap og eksponere den som en uforanderlig StateFlow. Dette sikrer at bare ViewModel kan endre tilstanden, respektere den enveis dataflyten og forhindre at viewet manipulerer dataene.
SharedFlow: Hendelsesbussen for unike handlinger
Hvis StateFlow er for «state», er SharedFlow for «events». Tenk deg at du vil vise en feildialog eller navigere til en annen skjerm. Hvis du bruker StateFlow, vil rotering av enheten føre til at den nye samleren mottar den siste verdien, og hendelsen vil utløses på nytt – en alvorlig feil. SharedFlow løser dette fordi den kan konfigureres med en replay-verdi på null.
Denne flyten er mye mer fleksibel og lar oss justere parametere som overløpsbufferen . Hvis bufferen fylles opp, kan vi velge å suspendere avsenderen eller forkaste den eldste eller nyeste verdien. En viktig fordel er at SharedFlow lar deg sende gjentatte verdier . Hvis du trenger å sende den samme "Tilkoblingsfeil"-meldingen tre ganger, vil SharedFlow gjøre det uten å nøle, mens StateFlow vil filtrere dem ut.
Teknisk sammenligning: StateFlow vs. SharedFlow vs. LiveData
For å unngå forvirring i et teknisk intervju eller når du designer arkitekturen din, er det viktig å vurdere de kritiske punktene. LiveData er enkelt og administrerer livssyklusen automatisk , men det er veldig knyttet til Android. StateFlow og SharedFlow, som er en del av Kotlin Coroutines, er plattformuavhengige , noe som forenkler enhetstesting og opprettelsen av rene domenelag i stor grad.
- StateFlow: Tvinger frem en startverdi, har .value, deduplikaterer verdier og er ideell for brukergrensesnitttilstander.
- DeltFlowDen krever ikke en startverdi, er konfigurerbar med tanke på avspilling, og er det riktige alternativet for flyktige hendelser.
- LiveDataDen krever ikke startverdi, den er klar over livssyklusen, men mindre kraftig i asynkrone transformasjoner.
Viktigheten av sikker høsting
En veldig vanlig feil er å utføre en `collect` innenfor et enkelt korrutineomfang i aktiviteten. Dette er farlig fordi flyten vil fortsette å behandle data selv når appen er i bakgrunnen , noe som kan forårsake krasj eller overdreven CPU-bruk. Den moderne løsningen er å bruke API-et `repeatOnLifecycle(Lifecycle.State.STARTED)`.
Denne funksjonen aktiverer samlingen når visningen er synlig, og avbryter den automatisk når den når STOPPET-tilstanden . For Jetpack Compose anbefales det å bruke `collectAsStateWithLifecycle()` , som integrerer denne logikken direkte og sikrer at applikasjonen er effektiv med enhetsressurser.
Å omdanne kalde strømmer til varme
Noen ganger har vi en flyt som kommer fra en database (som Room) eller et repository, og den er kald. For å gjøre den varm bruker vi operatorene `stateIn` eller `shareIn` . Disse operatorene krever et `CoroutineScope` og en oppstartsstrategi. Den vanligste er `SharingStarted.WhileSubscribed(5000)`.
Denne konfigurasjonen er genial fordi den holder strømmen aktiv så lenge det er abonnenter, og hvis skjermen er lukket, venter den i 5 sekunder før den stopper strømmen. Dette er avgjørende slik at strømmen ikke ødelegges og gjenskapes under en skjermrotasjon , og dermed unngår unødvendige forespørsler til serveren eller den lokale databasen.
Å mestre disse verktøyene innebærer å forstå at tilstanden må være vedvarende og deduplisert ved hjelp av StateFlow, mens engangshandlinger bør flyte gjennom SharedFlow. Ved å kombinere dette med livssyklusbevissthet og kaldflyttransformasjon ved hjelp av stateIn, oppnår vi en robust, fullstendig reaktiv Android-arkitektur optimalisert for ytelse i den virkelige verden på mobile enheter. Del denne veiledningen og hjelp andre med å lære om dette emnet.
