DisposableEffect — Jetpack Compose-da composable-funksiyadır, aşkar işə salma və sonradan resursların təmizlənməsini tələb edən əməliyyatlar üçün nəzərdə tutulub. Digər side-effect API-lərdən fərqli olaraq, DisposableEffect onDispose bloku təqdim edir ki, bu da komponent kompozisiyadan çıxdıqda və ya açar dəyişdikdə garantili şəkildə icra olunur. Bu, onu yerli abunəliklər, sensor dinləyiciləri və aparat resursları ilə işləmək üçün əvəzolunmaz edir. Android Developers Documentation (2025)-a görə, DisposableEffect Activity həyat dövründə onStart/onStop-a bənzər setup/teardown cütü tələb olunan bütün ssenarilərdə istifadə üçün tövsiyə olunur.
Əsas məqamlar
DisposableEffect — Jetpack Compose-da resursların idarə edilməsi üçün əsas vasitədir. Onun əsas xüsusiyyəti — composable-komponentin həyat dövrü başa çatdıqda onDispose blokunun garantili çağırışıdır. Bu davranış Android inkişafı üçün kritik əhəmiyyət daşıyır, çünki bağlanmamış sistem xidməti abunəlikləri yaddaş sızmalarına və tətbiqin qəzaya uğramasına səbəb ola bilər.
Korutin kontekstində asinxron işləyən LaunchedEffect-dən fərqli olaraq, DisposableEffect sinxron icra olunur. Bu o deməkdir ki, onun daxilində suspend-funksiyaları çağırmaq olmaz. Sinxronluq proqnozlaşdırıla bilənliyi təmin edir: əmin ola bilərsiniz ki, işəsalma kodu ilk renderdən əvvəl, təmizləmə kodu isə komponent yaddaşdan silinməzdən əvvəl icra olunacaq.
Jetpack Compose Sənədləşməsinə (2025) görə, DisposableEffect dörd əsas ssenaridə istifadə edilməlidir: (1) sistem xidmətlərinə abunəlik (sensorlar, LocationManager), (2) BroadcastReceiver qeydiyyatı, (3) korutinləri dəstəkləməyən callback əsaslı kitabxanalarla iş, (4) Compose komponentlərinin AndroidView vasitəsilə Legacy View sistemlərinə bağlanması.
class SensorManager(private val context: Context) {
fun startListening(callback: (Float) -> Unit) { /* register */ }
fun stopListening() { /* cancel */ }
}
@Composable
fun SensorDisplay() {
val sensorManager = remember { SensorManager(context) }
var value by remember { mutableStateOf(0f) }
DisposableEffect(Unit) {
sensorManager.startListening { value = it }
onDispose { sensorManager.stopListening() }
}
Text("Sensor: $value")
}
DisposableEffect-in daxili mexanikası kompozisiyanın həyat dövrü fazalarına əsaslanır. Composable-komponent kompozisiyaya daxil olduqda, DisposableEffect ötürülən kod blokunu çağırır. Bu blok onDispose lambdasını ehtiva edən DisposableEffectResult obyektini qaytarır. Kompozisiya bu nəticəni saxlayır və komponent kompozisiyanı tərk etdikdə onDispose-u çağırır — səbəbindən asılı olmayaraq (naviqasiya, valideyn vəziyyətinin dəyişməsi, LazyColumn-dan silinmə).
DisposableEffect-də açar mexanizmi LaunchedEffect ilə eyni işləyir: hər hansı açar dəyişdikdə əvvəlcə köhnə vəziyyət üçün onDispose icra olunur, sonra işəsalma bloku yeni açarlarla təkrar işə düşür. Bu, parametrlər dəyişdikdə resursu yenidən konfiqurasiya etməyə imkan verir. Məsələn, açar socket URL-idirsə, onun dəyişməsi ilə köhnə socket bağlanır və yeni socket açılır.
Vacibdir: onDispose bloku DisposableEffect-in məcburi elementidir. Blok daxilində onDispose çağırılmasa, kod kompilyasiya olunmayacaq. Kompilyatorun bu tələbi təmin edir ki, tərtibatçı resursun təmizlənməsini nəzərdən qaçırmasın, bu da abunəliklərin əl ilə idarə edilməsində tez-tez rast gəlinən səhvdir.
// Açar ilə düzgün istifadə
DisposableEffect(sensorType) {
val sensor = sensorManager.getDefaultSensor(sensorType)
sensorManager.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_NORMAL)
onDispose {
sensorManager.unregisterListener(listener)
}
}
// Bir DisposableEffect-də çoxlu resurslar
DisposableEffect(Unit) {
context.registerReceiver(receiver, intentFilter)
lifecycle.addObserver(observer)
onDispose {
context.unregisterReceiver(receiver)
lifecycle.removeObserver(observer)
}
}
Android tətbiqlərində yaddaş sızmaları tez-tez ekran bağlandıqdan sonra Activity və ya Context-ə istinadı saxlayan qeydiyyatdan keçməmiş dinləyicilər və abunəliklər səbəbindən yaranır. DisposableEffect bu problemi framework səviyyəsində həll edir: əgər tərtibatçı dinləyicini qeydiyyata almaq üçün DisposableEffect istifadə edibsə, onDispose komponentin başa çatmasının istənilən ssenarisində abunəliyi garantili şəkildə ləğv edir.
Bu, xüsusilə elementlərin skroll zamanı daim yaradıldığı və məhv edildiyi LazyColumn və LazyGrid üçün kritikdir. DisposableEffect olmadan, görünmə sahəsindən çıxan hər bir element aktiv abunəlik buraxardı. DisposableEffect ilə onDispose hər boşaldılan element üçün çağırılır və resursların element ekranı tərk edən kimi dərhal boşaldılmasını təmin edir.
Android Performance Patterns (Google, 2025)-a görə, bütün yerli abunəliklər üçün DisposableEffect istifadəsi Compose tətbiqlərində yaddaş sızmalarının sayını həyat dövrü callback-ləri ilə əl ilə idarəetmə ilə müqayisədə 60–70% azaldır. Sistem özü kompozisiyadan çıxma anını izləyir və hətta ekranın təcili bağlanmasında belə onDispose-un icrasını təmin edir.
| Resurs | DisposableEffect nə edir | DisposableEffect olmadan |
|---|---|---|
| BroadcastReceiver | register + onDispose → unregister | Receiver aktiv qalır |
| SensorManager | registerListener + onDispose → unregister | Sensor məlumat göndərməyə davam edir |
| Observable (Flow deyil) | subscribe + onDispose → unsubscribe | Callback istinadı saxlayır |
| TextureView / SurfaceView | setCallback + onDispose → removeCallback | Callback sızması |
| Socket / Channel | open + onDispose → close | Bağlantı açıq qalır |
DisposableEffect-in ən nümayişkaranə nümunələrindən biri — cihaz sensorları ilə işdir (akselerometr, giroskop, maqnitometr). Sensorlar işin sonunda məcburi qeydiyyatdan çıxarılma tələb edir, əks halda ekran bağlandıqdan sonra belə batareya enerjisini istehlak etməyə və məlumat göndərməyə davam edirlər.
Praktik nümunə: meyl bucağını ölçən tətbiq. DisposableEffect(Unit) komponent görünəndə akselerometr dinləyicisini qeydiyyata alır və onDispose-da qeydiyyatı ləğv edir. Sensor məlumatları mutableStateOf vasitəsilə vəziyyətə ötürülür, bu da UI-ni avtomatik yeniləyir. Ekran LazyColumn-da skroll edilirsə və element yox olursa, onDispose dərhal işə düşür — sensor bu element üçün məlumat göndərməyi dayandırır.
Sensor növü dəyişdikdə (məsələn, akselerometrdən giroskopa) sensorType açarı dəyişir, onDispose köhnə abunəliyi ləğv edir və yeni DisposableEffect bloku yeni sensoru qeydiyyata alır. Açarlar olmadan, hansı sensorun əvvəllər qeydiyyata alındığını əl ilə yoxlamaq və düzgün listener ilə unregisterListener çağırmaq lazım gələrdi — bu da səhvlərə səbəb ola bilər.
@Composable
fun SensorReadingScreen(sensorType: Int) {
val context = LocalContext.current
val sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager
var sensorValue by remember { mutableStateOf(0f) }
DisposableEffect(sensorType) {
val sensor = sensorManager.getDefaultSensor(sensorType)
val listener = SensorEventListener { event, _ ->
sensorValue = event.values[0]
}
sensorManager.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_NORMAL)
onDispose {
sensorManager.unregisterListener(listener)
}
}
Text("Dəyər: $sensorValue")
}
BroadcastReceiver — məcburi register / unregister cütü tələb edən klassik API nümunəsidir. Compose tətbiqində DisposableEffect müəyyən ekranın ömrü boyu qəbuledicinin qeydiyyatı üçün ideal uyğun gəlir. Ekrana daxil olduqda müvafiq IntentFilter ilə BroadcastReceiver qeydiyyata alınır, çıxdıqda isə onDispose-da avtomatik ləğv edilir.
Tipik ssenari — şəbəkə vəziyyətinin monitorinqi. DisposableEffect ConnectivityManager-də şəbəkə qoşulmasındakı dəyişikliklər barədə xəbərdarlıq edən qəbuledici qeydiyyata alır. Status dəyişdikdə (WiFi / mobil məlumat / şəbəkə yoxdur) composable vəziyyəti yenilənir və UI müvafiq göstəricini əks etdirir. Ekran bağlandıqda, onDispose qeydiyyatı garantili şəkildə ləğv edir — hətta tətbiq fon rejiminə keçsə belə.
ContextCompat.registerReceiver və RECEIVER_EXPORTED / RECEIVER_NOT_EXPORTED bayrağı (Android 14+) ilə qəbuledicilər üçün DisposableEffect istifadəsi məcburi olur, çünki sistem qəbuledicinin fəaliyyət sahəsinin açıq şəkildə göstərilməsini tələb edir. DisposableEffect, fəaliyyət sahəsinin ekranın ömrü ilə məhdudlaşdığını təmin edir ki, bu da Android-in yeni versiyalarının təhlükəsizlik tələbləri ilə üst-üstə düşür.
@Composable
fun NetworkStatusBanner() {
val context = LocalContext.current
var isConnected by remember { mutableStateOf(true) }
DisposableEffect(Unit) {
val receiver = BroadcastReceiver { _, _ ->
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
isConnected = cm.getActiveNetwork() != null
}
IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION).let { filter ->
context.registerReceiver(receiver, filter)
}
onDispose {
context.unregisterReceiver(receiver)
}
}
if (!isConnected) { ... }
}
Birinci kritik səhv — onDispose çağırışının olmaması. DisposableEffect bloku daxilindəki kod onDispose-u çağırmalıdır, əks halda kompilyasiya xətası baş verəcək. Bununla belə, tərtibatçılar bəzən onDispose-u şərt daxilinə yerləşdirməklə bundan yan keçməyə çalışırlar: if (condition) { onDispose { ... } }. Belə kod kompilyasiya olunacaq, lakin şərt yerinə yetirilməzsə onDispose qeydiyyata alınmayacaq — resurs heç vaxt boşaldılmayacaq.
İkinci səhv — DisposableEffect-in asinxron əməliyyatlar üçün istifadəsi. DisposableEffect sinxron olduğundan, onun daxilində delay() və ya await() çağırışları yazmaq olmaz. Əgər sonrakı təmizləmə ilə asinxron işəsalma lazımdırsa, LaunchedEffect (məlumat yükləmək üçün) və DisposableEffect (yerli resursların qurulması/təmizlənməsi üçün) kombinasiyasından və ya rememberCoroutineScope ilə ayrıca mexanizmdən istifadə edin.
Üçüncü səhv — DisposableEffect daxilində remember olmadan yeni obyektlərin yaradılması. Əgər effekt daxilində hər çağırışda obyektlər (sensor, listener, qəbuledici) yaradılırsa və açarlar tez-tez dəyişirsə, bu, həddindən artıq obyekt yaradılmasına və zibil yığımına gətirib çıxarır. Obyektlərin yaradılmasını remember və ya remember { ... } ilə DisposableEffect-dən kənara çıxarmaq, effekt daxilində isə yalnız qeydiyyat və ləğv etmək daha yaxşıdır.
Tez-tez verilən suallar
DisposableEffect sinxron işləyir və resursların aşkar təmizlənməsi üçün onDispose təqdim edir. LaunchedEffect korutində asinxron işləyir və açar dəyişdikdə və ya kompozisiyadan çıxdıqda onu avtomatik ləğv edir. Əgər resurs cleanup metodu (close, unregister, dispose) çağırışı tələb edirsə — DisposableEffect istifadə edin. Əməliyyat suspend-funksiyadırsa — LaunchedEffect istifadə edin.
Bəli, onDispose məcburidir — Kotlin kompilyatoru onun DisposableEffect bloku daxilində çağırılmasını tələb edir. onDispose çağırılmasa, kod kompilyasiya olunmayacaq. Bu, tərtibatçıların diqqətsizliyinin qarşısını almaq və hər açıq resursun kompozisiyadan çıxdıqda bağlanmasını təmin etmək üçün qəsdən edilib.
DisposableEffect bloku daxilində try-catch istifadə edin. Əgər resursun qeydiyyatı istisna yarada bilərsə (məsələn, sensor tapılmadı), onu try ilə əhatə edin və xətanı ayrıca vəziyyət vasitəsilə UI-də idarə edin. onDispose işəsalmanın uğurundan asılı olmayaraq çağırılmalıdır — onu finally blokuna və ya try bölməsinin sonuna yerləşdirin.
Tövsiyə edilmir. Flow üçün LaunchedEffect-i collectLatest ilə və ya .collectAsState() metodunu Lifecycle.repeatOnLifecycle ilə istifadə etmək daha yaxşıdır. DisposableEffect suspend-funksiyaları dəstəkləmir, ona görə də onun daxilində Flow-a abunəlik CoroutineScope vasitəsilə ayrıca korutin işə salmağı tələb edərdi ki, bu da kodu çətinləşdirir və sızma riskini artırır.
Məhdudiyyət yoxdur, lakin əlaqəli resursları bir DisposableEffect-də bir neçə əməliyyat və bir onDispose ilə qruplaşdırmaq tövsiyə olunur. Resurslar müstəqildirsə (məsələn, sensor və BroadcastReceiver), onları müxtəlif açarlarla ayrıca DisposableEffect-lərə bölmək daha yaxşıdır — bu, debug-u asanlaşdırır və bir açar dəyişdikdə bütün resursların arzuolunmaz yenidən yaradılmasının qarşısını alır.
Xülasə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun