DisposableEffect Jetpack Compose में एक composable फ़ंक्शन है जो उन कार्यों के लिए डिजाइन किया गया है जिन्हें स्पष्ट आरंभ और उसके बाद संसाधन सफाई की आवश्यकता होती है। अन्य side-effect API के विपरीत, DisposableEffect onDispose ब्लॉक प्रदान करता है जो घटक के संरचना से बाहर निकलने या कुंजी बदलने पर गारंटीपूर्वक निष्पादित होता है। यह इसे देशी सदस्यताओं, संवेदक श्रोताओं और हार्डवेयर संसाधनों के साथ काम करने के लिए अपरिहार्य बनाता है। Android Developers Documentation (2025) के अनुसार, DisposableEffect को सभी परिदृश्यों में उपयोग करने की अनुशंसा है जहाँ setup/teardown जोड़े की आवश्यकता हो, जो Activity जीवन चक्र में onStart/onStop के समान है।
मुख्य बातें
DisposableEffect Jetpack Compose में संसाधन प्रबंधन के लिए एक महत्वपूर्ण उपकरण है। इसकी मुख्य विशेषता composable घटक के जीवन चक्र के समाप्त होने पर onDispose ब्लॉक का गारंटीपूर्वक आह्वान है। यह व्यवहार Android विकास के लिए महत्वपूर्ण है, जहाँ सिस्टम सेवाओं की बंद न हुई सदस्यताएँ मेमोरी लीक और एप्लिकेशन क्रैश का कारण बन सकती हैं।
LaunchedEffect के विपरीत, जो कोरूटीन के असामकालिक संदर्भ में काम करता है, DisposableEffect ताल्यकालिक रूप से निष्पादित होता है। इसका मतलब है कि आप इसके अंदर suspend फ़ंक्शन नहीं बुला सकते। ताल्यकालिक निष्पादन पूर्वानुमानता सुनिश्चित करता है: आप निश्चित हो सकते हैं कि आरंभ कोड पहली रेंडरिंग से पहले और सफाई कोड मेमोरी से घटक हटाए जाने से पहले निष्पादित होता है।
Jetpack Compose दस्तावेज़ (2025) के अनुसार, DisposableEffect का उपयोग चार मुख्य परिदृश्यों में किया जाना चाहिए: (1) सिस्टम सेवाओं (संवेदक, LocationManager) की सदस्यता, (2) BroadcastReceiver पंजीयन, (3) कॉरूटीन का समर्थन न करने वाली callback-आधारित लाइब्रेरियों के साथ काम, (4) AndroidView के माध्यम से Compose घटकों को लगेसी View सिस्टम से जोड़ना।
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("संवेदक: $value")
}
DisposableEffect की आंतरिक क्रिया संरचना जीवन चक्र के चरणों पर आधारित है। जब कोई composable घटक संरचना में प्रवेश करता है, DisposableEffect पारित कोड ब्लॉक को निष्पादित करता है। यह ब्लॉक onDispose lambda युक्त DisposableEffectResult ऑब्जेक्ट लॉटाता है। संरचना इस परिणाम को संग्रहीत करती है और जब घटक संरचना छोड़ता है — कारण चाहे कुछ भी हो (नेविगेशन, मातृ अवस्था परिवर्तन, LazyColumn से हटाना) — onDispose को कॉल करती है।
DisposableEffect में कुंजी तंत्र LaunchedEffect के समान काम करता है: जब कोई कुंजी बदलती है, पहले onDispose पुरानी अवस्था के लिए निष्पादित होता है, फिर आरंभ ब्लॉक नई कुंजियों के साथ पुनः चलता है। यह आपको उसके पैरामीटर बदलने पर संसाधन को पुनः कॉन्फ़िगर करने की अनुमति देता है। उदाहरण के लिए, यदि कुंजी कोई सॉकेट URL है, तो इसके बदलने पर पुराना सॉकेट बंद होता है और नया खुलता है।
महत्वपूर्ण: onDispose ब्लॉक DisposableEffect का एक अनिवार्य तत्व है। यदि आप ब्लॉक के अंदर onDispose नहीं बुलाते हैं, तो कोड संकलित नहीं होगा। यह कंपाइलर आवश्यकता सुनिश्चित करती है कि डिव्लपर संसाधन सफाई प्रदान करना नहीं भूलता है, जो मैनुअल सदस्यता प्रबंधन में त्रुटियों का एक सामान्य कारण है।
// एक कुंजी के साथ सही उपयोग
DisposableEffect(sensorType) {
val sensor = sensorManager.getDefaultSensor(sensorType)
sensorManager.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_NORMAL)
onDispose {
sensorManager.unregisterListener(listener)
}
}
// एक DisposableEffect में एकाधिक संसाधन
DisposableEffect(Unit) {
context.registerReceiver(receiver, intentFilter)
lifecycle.addObserver(observer)
onDispose {
context.unregisterReceiver(receiver)
lifecycle.removeObserver(observer)
}
}
Android एप्लिकेशनों में मेमोरी लीक अक्सर अनिबंधित श्रोताओं और सदस्यताओं के कारण होती हैं जो स्क्रीन बंद होने के बाद भी Activity या Context का संदर्भ बनाए रखती हैं। DisposableEffect इस समस्या को फ्रेमवर्क स्तर पर हल करता है: यदि कोई डिव्लपर श्रोता पंजीकरण के लिए DisposableEffect का उपयोग करता है, तो onDispose किसी भी घटक समाप्ति परिदृश्य में सदस्यता रद्द करने की गारंटी देगा।
यह विशेष रूप से LazyColumn और LazyGrid के लिए महत्वपूर्ण है, जहाँ उपयोगकर्ता स्क्रॉल करता है तो तत्व लगातार बनते और नष्ट होते हैं। DisposableEffect के बिना, दृश्य क्षेत्र से गायब होने वाला प्रत्येक तत्व एक सक्रिय सदस्यता छोड़ देगा। DisposableEffect के साथ, प्रत्येक अनलोड किए गए तत्व के लिए onDispose कॉल किया जाता है, यह सुनिश्चित करते हुए कि तत्व के स्क्रीन छोड़ने के तुरंत बाद संसाधन मुक्त हो जाते हैं।
Android Performance Patterns (Google, 2025) के अनुसार, सभी देशी सदस्यताओं के लिए DisposableEffect का उपयोग जीवन चक्र callback के माध्यम से मैनुअल प्रबंधन की तुलना में Compose एप्लिकेशनों में मेमोरी लीक की संख्या में 60–70% की कमी करता है। सिस्टम स्वयं घटक के संरचना छोड़ने के क्षण का पता लगाता है और आपातकालीन स्क्रीन बंद होने पर भी onDispose के निष्पादन की गारंटी देता है।
| संसाधन | DisposableEffect क्या करता है | DisposableEffect के बिना |
|---|---|---|
| BroadcastReceiver | register + onDispose → unregister | रिसीवर सक्रिय रहता है |
| SensorManager | registerListener + onDispose → unregisterListener | संवेदक डेटा भेजना जारी रखता है |
| Observable (Flow नहीं) | subscribe + onDispose → unsubscribe | Callback संदर्भ बनाए रखता है |
| TextureView / SurfaceView | setCallback + onDispose → removeCallback | Callback लीक |
| Socket / Channel | open + onDispose → close | कनेक्शन खुला रहता है |
DisposableEffect के उपयोग के सबसे उदाहरणात्मक उदाहरणों में से एक डिवाइस संवेदकों (एक्सलरोमीटर, जायरोस्कॉप, मैग्नेटोमीटर) के साथ काम करना है। संवेदकों को काम पूरा होने पर अनिवार्य अपंजीकरण की आवश्यकता होती है, अन्यथा वे स्क्रीन बंद होने के बाद भी बैटरी की खपत करते रहते हैं और डेटा भेजते रहते हैं।
व्यावहारिक उदाहरण: झुकाव कोण मापन एप्लिकेशन। DisposableEffect(Unit) घटक प्रकट होने पर एक्सलरोमीटर श्रोता पंजीकृत करता है और onDispose में इसे अपंजीकृत करता है। संवेदक डेटा mutableStateOf के माध्यम से अवस्था में भेजी जाती है, जो स्वचालित रूप से UI को अपडेट करती है। यदि स्क्रीन LazyColumn में स्क्रॉल होती है और तत्व गायब हो जाता है, तो onDispose तुरंत चल जाता है — संवेदक उस तत्व के लिए डेटा भेजना बंद कर देता है।
संवेदक प्रकार बदलते समय (जैसे एक्सलरोमीटर से जायरोस्कॉप में), sensorType कुंजी बदलती है, onDispose पुरानी सदस्यता रद्द करता है, और नया DisposableEffect ब्लॉक नया संवेदक पंजीकृत करता है। बिना कुंजियों के, आपको मैनुअली जाँचना होगा कि कौन सा संवेदक पहले पंजीकृत किया गया था और सही श्रोता के साथ unregisterListener कॉल करना होगा — जो त्रुटि-प्रवण है।
@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("मान: $sensorValue")
}
BroadcastReceiver API का एक उत्तम उदाहरण है जिसे अनिवार्य register / unregister जोड़े की आवश्यकता होती है। कॉम्पोज़ एप्लिकेशन में, DisposableEffect किसी विशिष्ट स्क्रीन के जीवनकाल के लिए रिसीवर पंजीकृत करने के लिए आदर्श है। स्क्रीन में प्रवेश करने पर, आवश्यक IntentFilter के साथ एक BroadcastReceiver पंजीकृत होता है; बाहर निकलते समय, यह onDispose में स्वचालित रूप से रद्द हो जाता है।
एक विशिष्ट परिदृश्य नेटवर्क स्थिति निरीक्षण है। DisposableEffect ConnectivityManager के लिए एक रिसीवर पंजीकृत करता है जो नेटवर्क कनेक्शन परिवर्तनों के बारे में सूचित करता है। स्थिति बदलने पर (WiFi / मोबाइल डेटा / कोई नेटवर्क नहीं), composable अवस्था अपडेट होती है और UI संबंधित संकेतक प्रदर्शित करता है। जब स्क्रीन बंद होती है, onDispose पंजीयन रद्द करने की गारंटी देता है — भले ही एप्लिकेशन बैकग्रॉंड में चला जाए।
RECEIVER_EXPORTED / RECEIVER_NOT_EXPORTED झंडे (Android 14+) के साथ ContextCompat.registerReceiver का उपयोग करने वाले रिसीवर्स के लिए, DisposableEffect का उपयोग अनिवार्य हो जाता है क्योंकि सिस्टम को रिसीवर के दायरे के स्पष्ट विनिर्देशन की आवश्यकता होती है। DisposableEffect सुनिश्चित करता है कि दायरा स्क्रीन के जीवनकाल तक सीमित है, जो Android के नए संस्करणों की सुरक्षा आवश्यकताओं के अनुरूप है।
@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) { ... }
}
पहली गंभीर गलती onDispose कॉल का अभाव है। DisposableEffect ब्लॉक के अंदर कोड को onDispose कॉल करना चाहिए, अन्यथा संकलन त्रुटि होगी। हालाँकि, डिव्लपर कभी-कभी onDispose को शर्त में रखकर इसे बायपास करने की कोशिश करते हैं: if (condition) { onDispose { ... } }. ऐसा कोड संकलित हो जाएगा, लेकिन यदि शर्त पूरी नहीं होती है तो onDispose पंजीकृत नहीं होगा — संसाधन कभी मुक्त नहीं होगा।
दूसरी गलती असामकालिक संचालनों के लिए DisposableEffect का उपयोग करना है। चूँकि DisposableEffect ताल्यकालिक है, आप इसके अंदर delay() या await() कॉल नहीं लिख सकते। यदि आपको बाद में सफाई के साथ असामकालिक आरंभ की आवश्यकता है, तो LaunchedEffect (डेटा लोडिंग के लिए) और DisposableEffect (देशी संसाधनों को सेटअप/सफा करने के लिए) का संयोजन उपयोग करें, या rememberCoroutineScope के साथ एक अलग तंत्र का उपयोग करें।
तीसरी गलती remember के बिना DisposableEffect के अंदर नए ऑब्जेक्ट बनाना है। यदि ऑब्जेक्ट (संवेदक, listener, receiver) प्रत्येक कॉल पर प्रभाव के अंदर बनाए जाते हैं और कुंजियाँ बार-बार बदलती हैं, तो इससे अतिरिक्त ऑब्जेक्ट निर्माण और कचरा संग्रहण होता है। बेहतर है कि ऑब्जेक्ट निर्माण को remember या remember { ... } में DisposableEffect के बाहर ले जाएँ, और केवल उन्हें पंजीकृत और अपंजीकृत करें प्रभाव के अंदर।
अक्सर पूछे जाने वाले प्रश्न
DisposableEffect ताल्यकालिक रूप से काम करता है और संसाधनों की स्पष्ट सफाई के लिए onDispose प्रदान करता है। LaunchedEffect एक कोरूटीन में असामकालिक रूप से काम करता है और कुंजी बदलने या संरचना से बाहर निकलने पर स्वचालित रूप से इसे रद्द कर देता है। यदि किसी संसाधन को सफाई विधि (close, unregister, dispose) कॉल करने की आवश्यकता है — DisposableEffect का उपयोग करें। यदि ऑपरेशन एक suspend फ़ंक्शन है — LaunchedEffect का उपयोग करें।
हाँ, onDispose अनिवार्य है — Kotlin कंपाइलर को DisposableEffect ब्लॉक के अंदर इसे कॉल करने की आवश्यकता होती है। यदि आप onDispose कॉल नहीं करते हैं, तो कोड संकलित नहीं होगा। यह जानबूझकर किया गया है ताकि डिव्लपरों की भूलने से बचा जा सके और यह सुनिश्चित किया जा सके कि संरचना से बाहर निकलते समय प्रत्येक खुला संसाधन सही ढंग से बंद होगा।
DisposableEffect ब्लॉक के अंदर try-catch का उपयोग करें। यदि संसाधन पंजीयन एक अपवाद फेंक सकता है (जैसे संवेदक नहीं मिला), तो इसे try में लपेटें और अलग अवस्था के माध्यम से UI में त्रुटि को संभालें। onDispose को आरंभ की सफलता के बावजूद बुलाया जाना चाहिए — इसे finally ब्लॉक में या try अनुभाग के अंत में रखें।
अनुशंसित नहीं है। Flow के लिए, collectLatest के साथ LaunchedEffect या Lifecycle.repeatOnLifecycle के साथ .collectAsState() विधि का उपयोग करना बेहतर है। DisposableEffect suspend फ़ंक्शन्स का समर्थन नहीं करता, इसलिए इसके अंदर Flow की सदस्यता के लिए CoroutineScope के माध्यम से एक अलग कोरूटीन शुरू करने की आवश्यकता होगी, जो कोड को जटिल बनाता है और लीक का खतरा बढ़ाता है।
कोई सीमा नहीं है, लेकिन एक ही DisposableEffect में एकाधिक संचालनों और एक onDispose के साथ संबंधित संसाधनों को समूहबद्ध करने की अनुशंसा है। यदि संसाधन स्वतंत्र हैं (जैसे संवेदक और BroadcastReceiver), तो उन्हें अलग-अलग कुंजियों के साथ अलग DisposableEffects में विभाजित करना बेहतर है — यह डीबगिंग को सरल बनाता है और एक कुंजी बदलने पर सभी संसाधनों के अवांछनीय पुनर्निर्माण को रोकता है।
सारांश
हम एक मोबाइल एप्लिकेशन टर्नकी विकसित करेंगे
IT Sectr 2017 से स्टार्टअप और व्यवसायों के लिए iOS और Android एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।
यह भी पढ़ें