LaunchedEffect — egy composable-függvény a Jetpack Compose-ban, amely aszinkron műveletek végrehajtására szolgál egy korutinon belül, amely a komponens életciklusához van kötve. Elindít egy kódblokkot a composable-elem kompozícióba lépésekor, és automatikusan megszakítja azt a kilépéskor. Ez teszi a LaunchedEffect-et a fő eszközzé az adatok betöltéséhez, a Flow-ra való feliratkozáshoz és az időzítőkkel való munkához. A Android Documentation (2025) szerint a LaunchedEffect az aszinkron adatokkal dolgozó Jetpack Compose alkalmazások 85%-ban használatos.
Főbb pontok
LaunchedEffect — az öt side-effect API egyike a Jetpack Compose-ban, a DisposableEffect, SideEffect, SnapshotEffect és rememberCoroutineScope mellett. Különlegessége, hogy a kódot a composable-elem életciklusához kötött aszinkron korutin kontextusában hajtja végre. A szokásos callback-függvényekkel ellentétben a LaunchedEffect nem blokkolja a UI-t, és hosszan tartó műveleteket végezhet, mint például hálózati kérések vagy késleltetésre várás.
A motorháztető alatt a LaunchedEffect a kompozíció által biztosított CoroutineScope-ot használja. Ez a scope automatikusan megszakad, amikor a composable-elem elhagyja a kompozíciót. Egy ilyen kötés garantálja, hogy egyetlen korutin sem folytatódik a képernyő bezárása után — ez a fő különbség a ViewModel vagy Application scope globális korutinjaihoz képest.
Az Android Developers Blog (2025) szerint a LaunchedEffect kifejezetten a LiveData-observer minta helyettesítésére lett tervezve a Compose világában. Ahelyett, hogy a LiveData-ra observeAsState-n keresztül fizetnének fel és külön kezelnek a feliratkozást, a fejlesztők a LaunchedEffect-et használják a collectAsState-szel a Flow-n, ami kiszámíthatóbb életciklus-kezelést biztosít és kiküszöböli a kifejezett megszakítás nélküli feliratkozásokra jellemző memóriaszivárgásokat.
@Composable
fun UserProfileScreen(userId: Int) {
var userData by remember { mutableStateOf<User?>(null) }
LaunchedEffect(userId) {
val result = userRepository.fetchUser(userId)
userData = result
}
// Felhasználói felület a userData alapján
}
A LaunchedEffect legfontosabb mechanizmusa — a kulcsrendszer. A függvény első paramétere — vararg keys: Any? — meghatározza, hogy az effekt mikor induljon újra. A LaunchedEffect eltárolja a kulcsok előző értékeit, és minden összetételkor összehasonlítja azokat az újakkal. Ha legalább egy kulcs megváltozott (az equals()-en keresztül), a jelenlegi korutin megszakad és egy új indul.
Ha a kulcs például userId, akkor a felhasználó azonosítójának változásakor a LaunchedEffect automatikusan megszakítja a jelenlegi kérést és egy újat indít a frissített userId-val. Ez mentesíti a fejlesztőt az előző kérés kézi megszakítása és az adatok aktualitásának ellenőrzése alól — minden deklaratívan, kulcsokon keresztül van kezelve. Ez a megközelítés megfelel a Jetpack Compose reaktív paradigmájának.
Fontos szabály: ha állandót adunk át kulcsként — LaunchedEffect(Unit) — az effekt csak egyszer fut le a kompozícióba lépéskor, mint az onStart vagy onResume analógia a klasszikus Androidban. Ha nem adunk át kulcsokat — LaunchedEffect(Unit) — az effekt egyszer fut le. Ha üres zárójeleket adunk át — a LaunchedEffect nem fordul le, mert a kulcsok kötelező paraméterek.
// Egyszeri végrehajtás a képernyő megjelenésekor
LaunchedEffect(Unit) {
analytics.logScreenView("Profile")
}
// Újraindítás a userId változásakor
LaunchedEffect(userId) {
loadUserData(userId)
}
// Több kulcs
LaunchedEffect(userId, filter, sortOrder) {
fetchFilteredData(userId, filter, sortOrder)
}
Bár mindkét API a side effects körébe tartozik a Jetpack Compose-ban, a LaunchedEffect és a DisposableEffect alapvetően különböző feladatokat old meg. A LaunchedEffect aszinkron korutinokhoz való, kulcsok alapján történő újraindítási lehetőséggel, míg a DisposableEffect szinkron konfigurációs és erőforrás-tisztítási műveletekhez korutinok nélkül.
A fő különbség — az onDispose jelenléte a DisposableEffect-ben. A LaunchedEffect-nek nincs kifejezett tisztító blokkja: a korutin megszakítása automatikusan történik a kulcs változásakor vagy a kompozíció elhagyásakor, de a fejlesztő nem tud saját kódot beszúrni a megszakítás pillanatában. A DisposableEffect ezzel szemben rendelkezik egy onDispose blokkal, amely garantáltan végrehajtódik a kompozíció elhagyásakor, ami kritikus a natív erőforrások felszabadításához.
| Jellemző | LaunchedEffect | DisposableEffect |
|---|---|---|
| Végrehajtás | Aszinkron (korutin) | Szinkron |
| onDispose | Nincs (a korutin automatikus megszakítása) | Van (kifejezett tisztító blokk) |
| Kulcsok | Újraindítás + régi korutin megszakítása | onDispose végrehajtása + újrainicializálás |
| Tipikus alkalmazás | Hálózati kérések, Flow feliratkozások, időzítők | BroadcastReceiver, érzékelők, natív listener-ek |
| Megszakítás kilépéskor | Automatikus | onDispose-on keresztül |
A Google cikk „Compose Side Effects: Deep Dive” (2025) szerint a helyes választás a LaunchedEffect és a DisposableEffect között az erőforrás típusától függ: ha a művelet egy megszakítható korutin — használja a LaunchedEffect-et. Ha az erőforrás explicit close(), unregister() vagy dispose() hívást igényel — használja a DisposableEffect-et.
A LaunchedEffect leggyakoribb használati forgatókönyve — adatok betöltése a képernyő megnyitásakor. A minta egyszerű: a LaunchedEffect-en belül meghívódik a repository vagy UseCase suspend-függvénye, az eredmény egy state-változóhoz kerül, és a UI automatikusan újarajzolódik. A LaunchedEffect garantálja, hogy a képernyő újranyitásakor (például visszalépéskor) a betöltés újra megtörténik, ha a kulcsok megváltoztak.
A töltési állapotok megjelenítéséhez állapothármast használnak: Loading, Success, Error. A LaunchedEffect try-catch-be van csomagolva, és siker esetén state = Success(data), hiba esetén state = Error(exception) lesz beállítva. A UI reagál az állapotra és megjeleníti a megfelelő képernyőt: shimmer-töltő, adatok vagy hibaképernyő újrapróbálási gombbal.
Ha görgetéskor kell adatokat betölteni (pagináció), a LaunchedEffect-et összekapcsolják a LazyColumn és LazyListState elemekkel: a lista végének elérésekor a LaunchedEffect kulcs frissül (például az oldalszámláló), ami elindítja a következő adatrész betöltését.
@Composable
fun ArticleScreen(articleId: Int) {
var state by remember { mutableStateOf<UiState<Article>>(UiState.Loading) }
LaunchedEffect(articleId) {
state = UiState.Loading
state = try {
UiState.Success(articleRepository.fetch(articleId))
} catch (e: Exception) {
UiState.Error(e)
}
}
when (val s = state) {
is UiState.Loading -> ShimmerPlaceholder()
is UiState.Success -> ArticleContent(s.data)
is UiState.Error -> ErrorScreen(s.error)
{ // onRetry callback (state updates) }
}
}
A LaunchedEffect kulcsainak helyes használata — a kulcs a hatékony munkához az effektekkel (itt a szójáték tükrözi a lényeget). Ha a kulcs egy módosítható érték, amely gyakran változik (például a keresőlekérdezés szövege minden bevitt karakterkor), minden karakter megszakítja az előző korutint és elindít egy újat. A késleltetéssel történő kereséshez ez túlzás — jobb a debounce használata a korutinon belül.
A debounce megvalósításához a LaunchedEffect-en belül használja a delay()-t a fő művelet végrehajtása előtt. Például keresésnél: a LaunchedEffect(query) minden query változáskor elindul, de a kérés végrehajtása előtt delay(500) áll. Ha a felhasználó a következő karaktert 500 ms-nál korábban írja be, a korutin megszakad (a kulcs változása miatt) és egy új indul — így a kérés csak 500 ms szünet után kerül elküldésre.
Egy másik technika — a sealed class használata kulcsként. Ez lehetővé teszi annak pontos szabályozását, hogy az effekt mikor induljon újra. Például egy kulcs-csomagoló tartalmazza az azonosítót és egy kényszerített frissítési jelzőt: amikor a jelző false-ról true-ra változik, a LaunchedEffect újraindul, még akkor is, ha az azonosító nem változott. Ez a minta kényelmes a pull-to-refresh-hez.
// Keresés debounce 500ms-sel
LaunchedEffect(searchQuery) {
delay(500)
searchResults.value = repository.search(searchQuery)
}
// Pull-to-refresh kényszerített frissítéssel
data class RefreshKey(val id: Int, val refreshTrigger: Int)
var refreshTrigger by remember { mutableIntStateOf(0) }
LaunchedEffect(RefreshKey(userId, refreshTrigger)) {
articles = repository.loadUserArticles(userId)
}
Az első és leggyakoribb hiba — a LaunchedEffect használata kulcsok nélkül. Ha a LaunchedEffect { ... } argumentumok nélkül íródik, a korutin minden összetételkor újraindul, ami végtelen kéréshurokhoz vezet. A LaunchedEffect legalább egy kulcsot igényel — általában Unit-ot az egyszeri végrehajtáshoz.
Második hiba — a LaunchedEffect használatának kísérlete Flow-ra való feliratkozáshoz collect nélkül. Ha a LaunchedEffect-en belül collect-et hívnak a Flow-n, a korutin felfüggesztődik a Flow befejeződéséig (ami a StateFlow esetében soha nem történik meg), és az onDispose blokk nem tud normálisan befejeződni. A helyes megközelítés — a collectLatest használata, amely megszakítja az előző gyűjteményt egy új érték érkezésekor.
Harmadik hiba — beágyazott objektumok átadása kulcsként. Ha a kulcs egy data class módosítható mezőkkel (var), a LaunchedEffect előfordulhat, hogy nem ismeri fel a változást, mert a Compose az equals()-et használja összehasonlításra, és az a var-mezők esetén kiszámíthatatlanul műkődhet. Mindig változtathatatlan objektumokat (val) vagy primitíveket használjon a LaunchedEffect kulcsaiként.
Gyakran Ismételt Kérdések
Ha nem adunk át kulcsokat, a LaunchedEffect nem fordul le — a Kotlin legalább egy argumentumot követel a vararg paraméterekhez. Használja a LaunchedEffect(Unit)-ot egyszeri végrehajtáshoz a kompozícióba lépéskor, vagy adjon át konkrét értékeket, amelyek változásakor az effektnek újra kell indulnia.
Nem, a LaunchedEffect automatikusan megszakítja a korutint, amikor a composable elhagyja a kompozíciót, ami megelőzi a memóriaszivárgásokat. Azonban ha a LaunchedEffect-en belüli korutin egy closure-en keresztül tartja a referenciát egy Activity-re vagy Context-re, szivárgás lehetséges — használja a viewModelScope-ot a hosszú életű műveletekhez a ViewModel-ben.
A LaunchedEffect automatikusan végrehajtja a korutint a kompozícióba lépéskor, kulcsokhoz kötve. A rememberCoroutineScope egy scope-ot biztosít a korutinok kézi indításához, például válaszként az onItemClick-re. Használja a LaunchedEffect-et automatikus side effects-ekhez és a rememberCoroutineScope-ot korutinok indításához felhasználói események alapján.
Ha a LaunchedEffect kulcsának típusa instabil (például var vagy equals() nélküli osztály), a Compose előfordulhat, hogy nem ismeri fel, hogy az érték nem változott, és újraindítja az effektet minden összetételkor. Megoldás: használjon stabil típusokat (primitívek, stringek, data class val mezőkkel) vagy csomagolja a módosítható értékeket remember-be.
Nincs közvetlen mód a LaunchedEffect külről történő leállítására — a vezérlés kulcsokon keresztül történik. Változtassa meg a kulcsot a jelenlegi korutin megszakításához. Ha teljes kontrollra van szüksége a korutin életciklusa felett, használja a rememberCoroutineScope-ot Job-bal, és kézzel hívja a job.cancel()-t esemény vagy állapotváltozáskor.
Összefoglaló
Kulcsrakész mobilalkalmazást fejlesztünk
Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.
Olvassa el is