LaunchedEffect: nedir, coroutine’ler ve Jetpack Compose’da yönetim

Yazar: IT Sectr Yayınlanma: 2026-06-30 Okuma süresi: 9 dk

LaunchedEffect, Jetpack Compose’da bileşenin yaşam döngüsüne bağlı bir coroutine içinde asenkron işlemler gerçekleştirmek için tasarlanmış bir composable işlevidir. Composable öğe kompozisyona girdiğinde bir kod bloğunu başlatır ve çıktığında otomatik olarak iptal eder. Bu, LaunchedEffect’i veri yükleme, Flow’a abone olma ve zamanlayıcılarla çalışma için birincil araç haline getirir. Android Documentation (2025)’a göre, LaunchedEffect asenkron verilerle çalışan Jetpack Compose uygulamalarının %85’inde kullanılır.

Önemli Noktalar

  • LaunchedEffect — kompozisyon bağlamında coroutine başlatmak için yan etki API’si.
  • Anahtarlar — anahtarlar değiştiğinde coroutine iptal edilir ve yeni değerlerle yeniden başlatılır.
  • Otomatik iptal — bileşen kompozisyondan çıktığında coroutine otomatik olarak iptal edilir.
  • Asenkron — blok, Dispatchers.Main dağıtıcısıyla CoroutineScope içinde yürütülür.
  • Veri yükleme — tipik senaryo: ekran ilk göründüğünde ağdın yüklenmesi.

Jetpack Compose’da LaunchedEffect Nedir

LaunchedEffect, DisposableEffect, SideEffect, Effect ve rememberCoroutineScope ile birlikte Jetpack Compose’daki beş yan etki API’sinden biridir. Özelliği, kodu composable öğenin yaşam döngüsüne bağlı asenkron bir coroutine bağlamında yürütmesidir. Normal geri çağırma işlevlerinin aksine, LaunchedEffect kullanıcı arayüzünü engellemez ve ağ istekleri veya gecikme bekleme gibi uzun süreli işlemleri gerçekleştirebilir.

Perde arkasında, LaunchedEffect kompozisyon tarafından sağlanan bir CoroutineScope kullanır. Composable öğe kompozisyondan ayrıldığında bu kapsam otomatik olarak iptal edilir. Bu bağlama, ekran kapatıldıktan sonra hiçbir coroutine’in çalışmaya devam etmemesini garanti eder — bu, ViewModel veya Application kapsamındaki genel coroutine’lerden önemli bir farktır.

Android Developers Blog (2025)’a göre, LaunchedEffect özellikle Compose dünyasında LiveData-gözlemci modelini değiştirmek için tasarlanmıştır. observeAsState aracılığıyla LiveData’ya abone olmak ve aboneliği ayrı ayrı yönetmek yerine, geliştiriciler Flow üzerinde collectAsState ile LaunchedEffect kullanır; bu, daha öngörülebilir yaşam döngüsü yönetimi sağlar ve açık iptal olmadan aboneliklerin doğasında bulunan bellek sızıntılarını ortadan kaldırır.

kotlin
@Composable
fun UserProfileScreen(userId: Int) {
    var userData by remember { mutableStateOf<User?>(null) }
    
    LaunchedEffect(userId) {
        val result = userRepository.fetchUser(userId)
        userData = result
    }
    
    // userData tabanlı kullanıcı arayüzü
}

LaunchedEffect Anahtarlarla Nasıl Çalışır

LaunchedEffect’in en önemli mekanizması anahtar sistemidir. İşlevin ilk parametresi — vararg keys: Any? — efektin ne zaman yeniden başlatılması gerektiğini belirler. LaunchedEffect önceki anahtar değerlerini saklar ve her yeniden oluşturmada bunları yenileriyle karşılaştırır. En az bir anahtar değiştiyse (equals() aracılığıyla), geçerli coroutine iptal edilir ve yenisi başlatılır.

Anahtar örneğin userId ise, kullanıcı tanımlayıcısı değiştiğinde LaunchedEffect otomatik olarak geçerli isteği iptal eder ve güncellenmiş userId ile yeni bir istek başlatır. Bu, geliştiricinin önceki isteği manuel olarak iptal etme ve veri uygunluğunu kontrol etme zahmetinden kurtarır — her şey anahtarlar aracılığıyla bildirimsel olarak yönetilir. Bu yaklaşım, Jetpack Compose’un reaktif paradigmasıyla uyumludur.

Önemli kural: Bir sabiti anahtar olarak iletirseniz — LaunchedEffect(Unit) — efekt kompozisyona girerken yalnızca bir kez çalışır, klasik Android’deki onStart veya onResume’a benzer. Anahtar iletmezseniz, efekt kompozisyonda bir kez çalışır. Boş parantez iletirseniz, LaunchedEffect derlenmez çünkü anahtarlar zorunlu bir parametredir.

kotlin
// Ekran göründüğünde tek seferlik yürütme
LaunchedEffect(Unit) {
    analytics.logScreenView("Profile")
}

// userId değiştiğinde yeniden başlat
LaunchedEffect(userId) {
    loadUserData(userId)
}

// Birden çok anahtar
LaunchedEffect(userId, filter, sortOrder) {
    fetchFilteredData(userId, filter, sortOrder)
}

LaunchedEffect ve DisposableEffect Arasındaki Fark

Her iki API de Jetpack Compose’daki yan etkilere ait olmasına rağmen, LaunchedEffect ve DisposableEffect temel olarak farklı görevleri çözer. LaunchedEffect, anahtarlarla yeniden başlatma özelliğine sahip asenkron coroutine’ler için tasarlanmışken, DisposableEffect coroutine olmadan senkron kurulum ve temizlik işlemleri içindir.

Temel fark, DisposableEffect’te onDispose’un bulunmasıdır. LaunchedEffect’te açık bir temizlik bloğu yoktur: coroutine iptali, anahtar değiştiğinde veya kompozisyondan çıkıldığında otomatik olarak gerçekleşir, ancak geliştirici iptal anında özel kod ekleyemez. DisposableEffect ise, kompozisyondan çıkarken garantili olarak yürütülen bir onDispose bloğu sağlar; bu, yerel kaynakları serbest bırakmak için kritiktir.

ÖzellikLaunchedEffectDisposableEffect
YürütmeAsenkron (coroutine)Senkron
onDisposeHayır (otomatik iptal)Evet (açık temizlik bloğu)
AnahtarlarYeniden başlat + eski coroutine’i iptal etonDispose’u çalıştır + yeniden başlat
Tipik kullanımAğ istekleri, Flow abonelikleri, zamanlayıcılarBroadcastReceiver, sensörler, yerel dinleyiciler
Çıkışta iptalOtomatikonDispose aracılığıyla

Google’ın “Compose Side Effects: Deep Dive” (2025) makalesine göre, LaunchedEffect ve DisposableEffect arasındaki doğru seçim kaynak türüne göre belirlenir: işlem iptal edilebilir bir coroutine ise — LaunchedEffect kullanın. Kaynak, close(), unregister() veya dispose() için açık bir çağrı gerektiriyorsa — DisposableEffect kullanın.

LaunchedEffect İle Veri Yükleme

LaunchedEffect’in en yaygın kullanım durumu, bir ekran açıldığında veri yüklemektir. Model basittir: LaunchedEffect içinde, deponun veya UseCase’in bir askıya alma işlevi çağrılır, sonuç bir durum değişkenine atanır ve kullanıcı arayüzü otomatik olarak yeniden çizilir. LaunchedEffect, ekran yeniden açıldığında (örneğin, geri gezinme sırasında) anahtarlar değiştiyse yüklemenin yeniden yapılmasını garanti eder.

Yükleme durumlarını görüntülemek için üç durumlu bir model kullanılır: Loading, Success, Error. LaunchedEffect try-catch içine sarılır ve başarı durumunda state = Success(data), hata durumunda — state = Error(exception) ayarlanır. Kullanıcı arayüzü duruma tepki verir ve ilgili ekranı görüntüler: shimmer yükleyici, veri veya yeniden dene düğmesiyle hata ekranı.

Kaydırma sırasında veri yüklenmesi gerekiyorsa (sayfalama), LaunchedEffect LazyColumn ve LazyListState ile birleştirilir: listenin sonuna ulaşıldığında, LaunchedEffect anahtarı güncellenir (örneğin, bir sayfa sayacı) ve bu da verinin sonraki bölümünün yüklenmesini tetikler.

kotlin
@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) }
    }
}

Anahtar Yönetimi ve Yeniden Başlatma

LaunchedEffect anahtarlarının doğru kullanımı, efektlerle etkili bir şekilde çalışmanın anahtarıdır. Anahtar sık sık değişen değişebilir bir değerse (örneğin, her karakter girişinde arama sorgusu metni), her karakter önceki coroutine’i iptal eder ve yenisini başlatır. Debounce arama için bu aşırıdır — coroutine’in içinde debounce kullanmak daha iyidir.

LaunchedEffect içinde debounce uygulamak için, ana eylemi yürütmeden önce delay() kullanın. Örneğin, arama yaparken: LaunchedEffect(query) her sorgu değişikliğinde başlatılır, ancak isteği yürütmeden önce delay(500) vardır. Kullanıcı 500 ms geçmeden sonraki karakteri yazarsa, coroutine iptal edilir (anahtar değişikliği nedeniyle) ve yenisi başlatılır — böylece istek yalnızca girişte 500 ms’lik bir duraklamadan sonra gönderilir.

Başka bir teknik, anahtar olarak sealed class kullanmaktır. Bu, efektin ne zaman yeniden başlatılması gerektiği üzerinde hassas kontrol sağlar. Örneğin, bir sarmalayıcı anahtar bir tanımlayıcı ve zorunlu güncelleme bayrağı içerir: bayrak false’tan true’ya değiştiğinde, tanımlayıcı değişmemiş olsa bile LaunchedEffect yeniden başlatılır. Bu model, pull-to-refresh için kullanışlıdır.

kotlin
// 500ms debounce ile arama
LaunchedEffect(searchQuery) {
    delay(500)
    searchResults.value = repository.search(searchQuery)
}

// Zorunlu güncellemeyle pull-to-refresh
data class RefreshKey(val id: Int, val refreshTrigger: Int)
var refreshTrigger by remember { mutableIntStateOf(0) }

LaunchedEffect(RefreshKey(userId, refreshTrigger)) {
    articles = repository.loadUserArticles(userId)
}

LaunchedEffect ile Sık Yapılan Hatalar

İlk ve en yaygın hata, LaunchedEffect’i anahtarsız kullanmaktır. Bağımsız değişkenler olmadan LaunchedEffect { ... } yazarsanız, coroutine her yeniden oluşturmada yeniden başlatılır ve sonsuz bir istek döngüsüne yol açar. LaunchedEffect en az bir anahtar gerektirir — genellikle tek seferlik yürütme için Unit.

İkinci hata, Flow aboneliği için LaunchedEffect’i collect olmadan kullanmaya çalışmaktır. LaunchedEffect içinde bir Flow üzerinde collect çağırırsanız, coroutine Flow tamamlanana kadar askıya alınır (StateFlow durumunda asla gerçekleşmez). Doğru yaklaşım, yeni bir değer geldiğinde önceki toplamayı iptal eden collectLatest’i kullanmaktır.

Üçüncü hata, anahtar olarak iç içe nesneleri iletmektir. Anahtar değişebilir alanlara (var) sahip bir data class ise, LaunchedEffect değişikliği tanımayabilir çünkü Compose karşılaştırma için equals() kullanır ve bu, var alanlarıyla öngörülemez şekilde davranabilir. LaunchedEffect anahtarları olarak her zaman değişmez nesneler (val) veya ilkeller kullanın.

Sıkça Sorulan Sorular

LaunchedEffect’e anahtar iletilmezse ne olur?

Anahtar iletilmezse, LaunchedEffect derlenmez — Kotlin, vararg parametreleri için en az bir bağımsız değişken gerektirir. Kompozisyona girerken tek seferlik yürütme için LaunchedEffect(Unit) kullanın veya değiştiğinde efektin yeniden başlatılması gereken belirli değerleri iletin.

LaunchedEffect bellek sızıntısına neden olabilir mi?

Hayır, LaunchedEffect composable kompozisyondan ayrıldığında coroutine’i otomatik olarak iptal ederek bellek sızıntılarını önler. Ancak, LaunchedEffect içindeki coroutine bir kapatma yoluyla bir Activity veya Context referansı tutarsa, sızıntı mümkündür — ViewModel’de uzun süreli işlemler için viewModelScope kullanın.

LaunchedEffect ve rememberCoroutineScope arasındaki fark nedir?

LaunchedEffect, anahtar bağlamasıyla kompozisyona girerken otomatik olarak bir coroutine yürütür. rememberCoroutineScope, manuel coroutine başlatma için bir kapsam sağlar (örneğin, onItemClick’e yanıt olarak). Otomatik yan etkiler için LaunchedEffect’i ve kullanıcı olaylarına dayalı coroutine başlatma için rememberCoroutineScope’u kullanın.

Yeniden oluşturma sırasında LaunchedEffect neden birden çok kez yürütülür?

LaunchedEffect anahtarı kararsız bir türse (örneğin, var veya equals() olmayan bir sınıf), Compose değerin değişmediğini tanımayabilir ve her yeniden oluşturmada efekti yeniden başlatır. Çözüm: kararlı türler (ilkeller, dizeler, val alanlı data class) kullanın veya değişebilir değerleri remember içine sarın.

LaunchedEffect manuel olarak nasıl durdurulur?

Dışarıdan LaunchedEffect’i durdurmanın doğrudan bir yolu yoktur — kontrol anahtarlar aracılığıyla yönetilir. Geçerli coroutine’i iptal etmek için anahtarı değiştirin. Coroutine yaşam döngüsü üzerinde tam kontrole ihtiyacınız varsa, Job ile rememberCoroutineScope kullanın ve bir olay veya durum değişikliğinde manuel olarak job.cancel() çağrısı yapın.

Özet

  • LaunchedEffect — composable yaşam döngüsüne bağlı asenkron coroutine’leri başlatmak için Jetpack Compose’da yan etki API’si.
  • Anahtarlar — anahtar tabanlı yeniden başlatma sistemi: anahtar değişimi geçerli coroutine’i iptal eder ve güncellenmiş parametrelerle yenisini başlatır.
  • Otomatik iptal — composable kompozisyondan ayrıldığında coroutine otomatik olarak iptal edilir, bellek sızıntılarını önler.
  • Veri yükleme — tipik model: Loading, Success, Error durum yönetimiyle ağdaki verileri yüklemek için LaunchedEffect(anahtar).
  • Debounce — LaunchedEffect içinde delay() ile uygulanır: gecikme süresi dolmadan anahtar değişirse coroutine iptal edilir.
  • Flow aboneliği — LaunchedEffect içinde doğru Flow işleme için collect yerine collectLatest kullanın.
  • Kararlı anahtarlar — öngörülebilir davranış için anahtar olarak yalnızca değişmez türler (val, ilkeller, data class) kullanın.

Anahtar teslim bir mobil uygulama geliştireceğiz

IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.

Projeyi tartış

Ayrıca okuyun