अध्याय 26: असिंक्रोनस कैमरा प्रोग्रामिंग (Asynchronous Camera Programming)
सारांश (Summary)
अध्याय 7 से 9 में लिखे गए कोड को याद करें। CameraManager के अंदर CameraDevice कॉलबैक, उसके अंदर CaptureSession कॉलबैक, और फिर ImageReader लिसनर। यह "कॉलबैक हेल (callback hell)" है। हर स्तर पर एरर हैंडलिंग और रिसोर्स मैनेजमेंट बहुत मुश्किल हो जाता है।
यह अध्याय उस पूरी उलझन को साफ करने के लिए है। हम Kotlin Coroutines और Flow का उपयोग करके इस स्पगेटी कोड को एक सीधी, पढ़ने योग्य और टेस्ट करने योग्य पाइपलाइन में बदलेंगे।
कॉलबैक हेल (Callback Hell) क्यों एक समस्या है?
पुराने तरीके में, अगर फोटो लेते समय कोई एरर आता था, तो आपको चार अलग-अलग जगहों पर close() कॉल करना पड़ता था। यदि एक भी मिस हो गया, तो कैमरा लीक हो जाता है और फोन रीबूट होने तक काम नहीं करता।
कोरूटीन के साथ, हम इसे इस तरह बदल देते हैं:
openCameraAwait() -> createCaptureSessionAwait() -> captureAwait()
यह सीधा, सरल और मैनेज करने में आसान है।
वन-शॉट ऑपरेशंस के लिए कोरूटीन: suspendCancellableCoroutine
किसी भी कॉलबैक-आधारित API (जैसे openCamera) को suspend फंक्शन में बदलने के लिए हम suspendCancellableCoroutine का उपयोग करते हैं।
इसका नियम सरल है:
- API को कॉल करें।
- सफलता पर
cont.resume(value)कॉल करें। - एरर आने पर
cont.resumeWithException(error)कॉल करें। - कैंसिलेशन होने पर कैमरा बंद करने का लॉजिक लिखें।
अब आप withTimeout का उपयोग कर सकते हैं ताकि अगर कैमरा 5 सेकंड में न खुले, तो ऐप खुद को संभाल सके।
निरंतर स्ट्रीम के लिए Flow
प्रीव्यू फ्रेम या सेंसर मेटाडेटा जैसी चीज़ों के लिए जो लगातार आती रहती हैं, हम callbackFlow का उपयोग करते हैं।
उदाहरण: ImageReader को Flow में बदलना
जब भी एक नया इमेज फ्रेम आता है, वह Flow में 'emit' हो जाता है। जैसे ही आप Flow का कलेक्शन बंद करते हैं, लिसनर अपने आप हट जाता है और रिसोर्स फ्री हो जाते हैं। कोई लीक नहीं!
रिएक्टिव UI (Reactive UI)
Flow का असली जादू 'composition' में है। आप प्रीव्यू FPS, एक्सपोज़र स्टेट और "रेडी" इंडिकेटर को एक साथ मिलाकर एक uiState बना सकते हैं जो खुद को अपडेट करता रहता है।
थ्रेड सेफ्टी (Thread Safety) के नियम
- मेन थ्रेड पर कभी न खेलें:
openCamera()याcharacteristics.get()जैसे कॉल मेन थ्रेड को 1 सेकंड तक ब्लॉक कर सकते हैं, जिससे ऐप अटक (ANR) सकता है। हमेशाDispatchers.Defaultया किसी खास बैकग्राउंड थ्रेड का उपयोग करें। - Mutex का उपयोग करें: यदि एक थ्रेड डेटा लिख रहा है और दूसरा पढ़ रहा है, तो डेटा करप्शन से बचने के लिए
Mutex.withLockका उपयोग करें।
सारांश (Summary)
Camera2 के कॉलबैक-आधारित डिज़ाइन को Kotlin Coroutines और Flow के माध्यम से एक साफ, लीनियर पाइपलाइन में बदला जा सकता है। suspendCancellableCoroutine एक बार होने वाले काम (जैसे कैमरा खोलना) के लिए है, और callbackFlow लगातार आने वाले डेटा (जैसे वीडियो फ्रेम) के लिए। यह न केवल कोड को छोटा बनाता है, बल्कि उसे अधिक सुरक्षित और बग-फ्री भी बनाता है।
आगे क्या है
अब आपके पास एक मजबूत ऐप बनाने के टूल्स हैं। लेकिन आप यह कैसे सुनिश्चित करेंगे कि यह 24,000+ अलग-अलग Android मॉडलों पर सही काम करेगा? अध्याय 27 में हम कैमरा टेस्टिंग (Camera Testing) और ऑटोमेटेड वैलिडेशन के बारे में सीखेंगे।