SideEffect, Jetpack Compose’da her başarılı yeniden oluşturmada (recomposition) iletilen kod bloğunu çalıştıran bir composable işlevidir. LaunchedEffect ve DisposableEffect’in aksine, SideEffect anahtarlara bağlı değildir ve temizleme bloğu yoktur — her işlemeden sonra Compose durumunu harici sistemlerle senkronize eder. Bu, onu geri çağırma işlevlerini güncellemek, ViewPager ile senkronize etmek ve Analytics SDK’ya veri göndermek için ideal hale getirir. Android Developers Documentation (2025)’a göre SideEffect, Compose başarılı bir yeniden oluşturmayı onayladıktan sonra kesin olarak çalıştırılır ve yeniden oluşturma atlanırsa çalıştırılmaz.
Ana Noktalar
SideEffect, Jetpack Compose’daki en basit yan etki API’sidir. Bir composable bileşeninin her başarılı yeniden oluşturmasında bir kod bloğu çalıştırır. Burada “başarılı” kelimesi anahtardır: Compose yeniden oluşturmanın gerekli olmadığına karar verirse (örneğin, tüm giriş parametreleri değişmemişse ve sonuç aynı olacaksa), SideEffect çalıştırılmaz. Bu, senkronizasyon bloğunun yalnızca kullanıcı arayüzü gerçekten değiştiğinde çağrılmasını sağlar.
SideEffect’in ana kullanım durumu, Compose durumunu Compose ağacının parçası olmayan nesnelerle senkronize etmektir. Tipik örnekler şunları içerir: Legacy View sisteminde bir geri çağırma işlevini güncelleme, ViewPager’a mevcut durumu aktarma, görüntülenen veriler değiştiğinde bir Analiz SDK’sına olay gönderme ve harici bir formatta güncellemeler bekleyen harita SDK’larıyla senkronize etme.
Android Developer Blog (2025)’a göre SideEffect genellikle remember ile birlikte kullanılır: remember bir nesneyi (örneğin bir geri çağırma) korur ve SideEffect bir bağımlılık değiştiğinde onu günceller. Bu model, dinleyici nesnelerini kabul eden ve güncellemede onları yeniden oluşturmayan kütüphaneler için özellikle önemlidir — SideEffect olmadan, dinleyici mevcut duruma eski bir referans tutar.
@Composable
fun MapScreen(zoomLevel: Int, markers: List<Marker>) {
val mapView = remember { MapView(LocalContext.current) }
SideEffect {
mapView.setZoom(zoomLevel)
mapView.updateMarkers(markers)
}
AndroidView(factory = { mapView })
}
SideEffect’i anlamak için Jetpack Compose’un yürütme aşamalarını anlamanız gerekir. Compose her kare için üç aşamadan geçer: Composition (ne gösterileceği), Layout (nerede gösterileceği), Drawing (nasıl gösterileceği). SideEffect, Composition aşamasının sonunda çalıştırılır — tüm composable işlevler çalıştıktan sonra, ancak Layout aşamasından önce. Bu, SideEffect’in yeniden oluşturmadan sonra tüm değişkenlerin son durumunu görmesini sağlar.
Yaşam döngüsündeki bu konum önemli bir avantaj sağlar: SideEffect, içinde durum değiştirilse bile sonsuz yeniden oluşturmaya neden olamaz. Oluşturmadan sonra çalıştığı için, SideEffect içinde yapılan değişiklikler yalnızca sonraki karede uygulanacaktır — bu, bir composable işlevinin gövdesi içindeki tipik durum değişikliği döngülerini önler (oluşturma içindeki setState’in mevcut oluşturma bitmeden önce yeni bir oluşturmayı tetiklemesi).
Başka bir özellik de SideEffect’in anahtarlarla optimize edilmemesidir. Hangi belirli durumun değiştiğine bakılmaksızın her yeniden oluşturmada çalışır. Daha hassas kontrole ihtiyacınız varsa (yalnızca belirli bir parametre değiştiğinde çalıştırın), anahtarlarla LaunchedEffect kullanın veya SideEffect’i remember aracılığıyla bir değişiklik kontrolüne sarın.
// SideEffect optimized with remember
var currentZoom by remember { mutableIntStateOf(zoomLevel) }
SideEffect {
if (currentZoom != zoomLevel) {
map.animateToZoom(zoomLevel)
currentZoom = zoomLevel
}
}
// Without this check SideEffect would call animateToZoom
// on every recomposition, even if zoomLevel didn't change
SideEffect için en yaygın pratik senaryo, mevcut durumu yakalayan geri çağırma işlevlerini güncellemektir. Jetpack Compose’da buna “geri çağırma yaşam döngüsü yönetimi” denir. Sorun şudur: Kotlin’deki lambda ifadeleri değişkenleri referansla yakalar ve bir geri çağırma bir değerle oluşturulup daha sonra değişken değişirse — geri çağırma eski değeri kullanmaya devam eder.
Bir örnek düşünün: Android için Google Maps SDK, setOnCameraMoveListener() aracılığıyla bir OnCameraMoveListener nesnesini kabul eder. isTrackingEnabled’i yakalayan bir lambda iletirseniz, isTrackingEnabled değiştiğinde lambda güncellenmez — Maps SDK, eski verilerle eski geri çağırmayı çağırmaya devam eder. SideEffect bu sorunu çözer: her yeniden oluşturmada dinleyiciyi yeniden ayarlar ve SDK’nın her zaman en son durumla güncel lambda’yı kullanmasını sağlar.
Android için Maps SDK Dokümantasyonu (2025)’a göre Google, Maps’i Jetpack Compose ile entegre ederken tam olarak bu modeli önerir. Benzer bir yaklaşım, WebView, VideoView, TextureView ve set yöntemleri aracılığıyla geri çağırmaları kabul eden diğer View tabanlı bileşenler için kullanılır. SideEffect, her durum değişikliğinde geri çağırmaların güncel olmasını sağlar.
@Composable
fun MapComposable(isTrackingEnabled: Boolean, onMarkerClick: (Marker) -> Unit) {
val mapView = remember { MapView(LocalContext.current) }
SideEffect {
mapView.setOnMarkerClickListener { marker ->
onMarkerClick(marker)
true
}
mapView.isTrafficEnabled = isTrackingEnabled
}
AndroidView(factory = { mapView })
}
SideEffect için bir diğer önemli senaryo, kullanıcı arayüzü durumu değiştiğinde analiz sistemlerine olay göndermektir. Örneğin, bir kullanıcı Compose ekranı içindeki bir TabLayout’da sekmeleri değiştirdiğinde, SideEffect mevcut seçili sekme durumunu Firebase Analytics veya AppsFlyer’a aktarabilir. Seçili sekme her değiştiğinde (ve yeniden oluşturma gerçekleştiğinde), SideEffect ilgili olayı gönderir.
Olayları doğrudan onClick veya onTabSelected içinde göndermekten farkı, SideEffect’in herhangi bir kaynaktan gelen durum değişikliklerinde tetiklenmesidir — yalnızca kullanıcı eylemleri değil, aynı zamanda programatik değişiklikler, ekran dönüşünden sonra durum geri yükleme veya Deep Links de buna dahildir. Bu, SideEffect’i değişiklik kaynağından bağımsız evrensel bir senkronizasyon mekanizması haline getirir.
Firebase En İyi Uygulamalar (Google, 2025)’a göre, SideEffect aracılığıyla analiz olayları göndermek, kullanıcı yolculuğunun daha eksiksiz bir resmini sağlar çünkü doğrudan kullanıcı eylemi olmadan gerçekleşenler de dahil olmak üzere tüm durum değişikliklerini yakalar. Ancak aşırıya kaçmamak önemlidir: her analiz olayı bir ağ isteğidir, bu nedenle sık değişen durumlar (kaydırma konumu, parmak koordinatları) için SideEffect uygun değildir — debounce kullanın veya yalnızca önemli değişikliklerde olay gönderin.
@Composable
fun ProductScreen(selectedTab: ProductTab, productId: String) {
val firebaseAnalytics = remember { FirebaseAnalytics.getInstance(LocalContext.current) }
SideEffect {
val params = Bundle().apply {
putString(FirebaseAnalytics.Param.CONTENT_TYPE, selectedTab.name)
putString(FirebaseAnalytics.Param.ITEM_ID, productId)
}
firebaseAnalytics.logEvent( FirebaseAnalytics.Event.VIEW_ITEM, params)
}
// UI with TabRow and selected tab
}
SideEffect ve LaunchedEffect arasındaki seçim iki faktöre bağlıdır: asenkron yürütmenin gerekli olup olmadığı ve anahtar tabanlı kontrolün gerekli olup olmadığı. SideEffect senkrondur ve her yeniden oluşturmada çalışır. LaunchedEffect asenkrondur (coroutine) ve yalnızca bir anahtar değiştiğinde çalışır, her yeniden oluşturmada değil.
| Özellik | SideEffect | LaunchedEffect |
|---|---|---|
| Yürütme | Her yeniden oluşturmada | Anahtar değişiminde |
| Asenkron | Senkron | Coroutine |
| Anahtarlar | Hayır | Evet (vararg) |
| Temizlik | Hayır | Otomatik coroutine iptali |
| Tipik kullanım | Geri çağırmalar, analiz, görünüm senkronizasyonu | Yükleme, Flow aboneliği, zamanlayıcılar |
Pratikte, yan etki kullanım durumlarının %70’i LaunchedEffect (asenkron işlemler, veri yükleme), %20’si DisposableEffect (temizlikli kaynaklar) ve yalnızca %10’u SideEffect (geri çağırma senkronizasyonu) tarafından karşılanır. SideEffect, sınırlı bir görev yelpazesi için özelleşmiş bir araçtır, ancak bu görevlerde vazgeçilmezdir.
Ana hata SideEffect içinde Compose durumunu değiştirmektir. SideEffect doğrudan sonsuz döngüye neden olmasa da (oluşturma aşamasından sonra çalıştığı için), aşırı yeniden oluşturmaları tetikleyebilir. SideEffect içinde durum değiştirilirse (mutableStateOf), sonraki karede yeni bir yeniden oluşturmayı tetikler, bu da tekrar SideEffect’i çalıştırır — ve bu stabilizasyona kadar devam eder. Bu sonsuz bir döngü değildir, ancak framework için gereksiz iştir.
İkinci hata SideEffect içinde ağır hesaplamalar yapmaktır. SideEffect her yeniden oluşturmada çağrıldığından ve yeniden oluşturmalar saniyede düzinelerce kez gerçekleşebileceğinden (animasyonlar, kaydırma sırasında), SideEffect içindeki herhangi bir ağır kod kare düşmelerine yol açar. Ağır işlemleri oluşturma dışına taşıyın — bir coroutine’e (LaunchedEffect) veya derivedStateOf / remember aracılığıyla hesaplayın.
Üçüncü hata SideEffect’i asenkron kod için kullanmaya çalışmaktır. SideEffect bir suspend işlevi değildir, bu nedenle delay(), await(), collect() ve diğer coroutine işlemleri içinde derlenmez. Yeniden oluşturmadan sonra asenkron bir eylem gerçekleştirmeniz gerekiyorsa, LaunchedEffect ile birlikte snapshotFlow { ... } kullanın veya rememberCoroutineScope aracılığıyla bir coroutine başlatın.
Sıkça Sorulan Sorular
Evet, SideEffect her başarılı oluşturmada çalışır, ilki de dahil — bileşen ekranda ilk kez göründüğünde. Bu, onu LaunchedEffect(Unit)’ten ayırır; LaunchedEffect(Unit) de ilk oluşturmada bir kez çalışır ancak sonraki yeniden oluşturmalarda çalışmaz (anahtar değişmediyse).
Hayır, SideEffect oluşturma aşamasından sonra çalışır — içinde yapılan değişiklikler yalnızca sonraki karede uygulanır ve bu da döngüleri önler. Ancak SideEffect içinde sık sık durum değiştirmek, bir yeniden oluşturma zincirine neden olarak performansı düşürebilir. SideEffect içinde durumu yalnızca gerçekten gerekli olduğunda değiştirin.
SideEffect her yeniden oluşturmada senkron olarak çalışır. snapshotFlow, Compose durumundan bir Flow oluşturur ve reaktif değişiklik işleme için LaunchedEffect içinde collectLatest ile kullanılabilir. snapshotFlow, debounce, filter veya distinctUntilChanged ile değişikliklere tepki vermeniz gereken durumlar için uygundur — senkron SideEffect’te bu imkansızdır.
Android Studio Compose Modifier Debugger kullanın veya bileşen adı ve çağrı sıklığı ile günlük kaydı ekleyin. SideEffect beklenenden daha sık çalışıyorsa, üst bileşenin durumunun gereksiz yere değişip değişmediğini kontrol edin. Optimizasyon: kullanıcı arayüzünün kararlı kısımlarını unstable notlarıyla ayrı composable işlevlerine çıkararak yeniden oluşturma sayısını azaltın.
Evet, farklı amaçlar için aynı bileşende kullanılabilirler. DisposableEffect bir kaynağın kurulumu ve temizliğinden (bir kez) sorumluyken, SideEffect her yeniden oluşturmada mevcut durumun bu kaynakla senkronizasyonunu yönetir. Tipik bir örnek: DisposableEffect bir API aracılığıyla bir geri çağırma kaydeder ve SideEffect her değişiklikte bu geri çağırmadaki yakalanan verileri günceller.
Özet
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.
Ayrıca okuyun