Android ऐप्लिकेशन फ़्रेमवर्क का यूज़र इंटरफ़ेस (यूआई), ऑब्जेक्ट के क्रम पर आधारित होता है. यह क्रम View से शुरू होता है. सभी यूज़र इंटरफ़ेस (यूआई) एलिमेंट को मेज़रमेंट और लेआउट प्रोसेस से गुज़रना होता है. इससे उन्हें आयताकार जगह में फ़िट किया जा सकता है. इसके बाद, फ़्रेमवर्क सभी दिखने वाले व्यू ऑब्जेक्ट को उस सर्फ़ेस पर रेंडर करता है जिसे WindowManager ने ऐप्लिकेशन को फ़ोरग्राउंड में लाने के दौरान सेट अप किया था. ऐप्लिकेशन की यूज़र इंटरफ़ेस (यूआई) थ्रेड, हर फ़्रेम के लिए लेआउट और रेंडरिंग को बफ़र करती है.
SurfaceView
SurfaceView एक ऐसा कॉम्पोनेंट है जिसका इस्तेमाल, व्यू हैरारकी में कंपोज़िट लेयर को एम्बेड करने के लिए किया जा सकता है. SurfaceView, अन्य व्यू की तरह ही लेआउट पैरामीटर लेता है. इसलिए, इसे किसी अन्य व्यू की तरह ही बदला जा सकता है. हालांकि, SurfaceView का कॉन्टेंट पारदर्शी होता है.
GL कॉन्टेक्स्ट या मीडिया डिकोडर जैसे किसी बाहरी बफ़र सोर्स की मदद से रेंडर करने पर, आपको बफ़र सोर्स से बफ़र कॉपी करने होंगे, ताकि उन्हें स्क्रीन पर दिखाया जा सके. SurfaceView का इस्तेमाल करके ऐसा किया जा सकता है.
जब SurfaceView का व्यू कॉम्पोनेंट दिखने वाला होता है, तो फ़्रेमवर्क, SurfaceControl से SurfaceFlinger से नया सरफेस पाने का अनुरोध करने के लिए कहता है. सरफ़ेस बनाने या मिटाने पर कॉलबैक पाने के लिए, SurfaceHolder इंटरफ़ेस का इस्तेमाल करें. डिफ़ॉल्ट रूप से, फ़्रेमवर्क नए बनाए गए सर्फ़ेस को ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) सर्फ़ेस के पीछे रखता है. डिफ़ॉल्ट Z-ऑर्डरिंग को बदलकर, नए सर्फ़ेस को सबसे ऊपर रखा जा सकता है.
SurfaceView की मदद से रेंडरिंग करना उन मामलों में फ़ायदेमंद होता है जहां आपको किसी अलग सरफेस पर रेंडर करना होता है. जैसे, Camera API या OpenGL ES कॉन्टेक्स्ट की मदद से रेंडर करना. SurfaceView का इस्तेमाल करके रेंडर करने पर, SurfaceFlinger सीधे तौर पर स्क्रीन पर बफ़र कंपोज़ करता है. SurfaceView के बिना, आपको बफ़र को किसी ऑफ़स्क्रीन सर्फ़ेस पर कंपोज़िट करना होगा. इसके बाद, इसे स्क्रीन पर कंपोज़िट किया जाएगा. इसलिए, SurfaceView के साथ रेंडर करने से अतिरिक्त काम नहीं करना पड़ता. SurfaceView के साथ रेंडर करने के बाद, गतिविधि के लाइफ़साइकल के साथ समन्वय बनाने के लिए यूज़र इंटरफ़ेस (यूआई) थ्रेड का इस्तेमाल करें. साथ ही, ज़रूरत पड़ने पर व्यू के साइज़ या पोज़िशन में बदलाव करें. इसके बाद, हार्डवेयर कंपोज़र, ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) और अन्य लेयर को एक साथ जोड़ता है.
नया सर्फ़ेस, BufferQueue का प्रोड्यूसर है. इसका कंज्यूमर, SurfaceFlinger लेयर है. किसी भी ऐसे तरीके से प्लैटफ़ॉर्म को अपडेट किया जा सकता है जो BufferQueue को फ़ीड कर सकता है. जैसे, प्लैटफ़ॉर्म से उपलब्ध कराए गए Canvas फ़ंक्शन, EGLSurface अटैच करना और GLES की मदद से प्लैटफ़ॉर्म पर ड्रॉ करना या मीडिया डिकोडर को प्लैटफ़ॉर्म पर लिखने के लिए कॉन्फ़िगर करना.
SurfaceView और गतिविधि की लाइफ़साइकल
SurfaceView का इस्तेमाल करते समय, मुख्य यूज़र इंटरफ़ेस (यूआई) थ्रेड के अलावा किसी अन्य थ्रेड से सरफेस रेंडर करें.
SurfaceView वाली किसी गतिविधि के लिए, दो अलग-अलग लेकिन एक-दूसरे पर निर्भर स्टेट मशीन होती हैं:
- ऐप्लिकेशन
onCreate
/onResume
/onPause
- सतह बनाई गई/बदली गई/मिटाई गई
गतिविधि शुरू होने पर, आपको इस क्रम में कॉलबैक मिलते हैं:
onCreate()
onResume()
surfaceCreated()
surfaceChanged()
'वापस जाएं' पर क्लिक करने से आपको यह दिखेगा:
onPause()
surfaceDestroyed()
(यह तब कॉल किया जाता है, जब सर्फ़ेस बंद होने वाला होता है)
स्क्रीन को घुमाने पर, गतिविधि बंद हो जाती है और फिर से शुरू होती है. इससे आपको पूरा साइकल मिलता है. isFinishing()
को देखकर पता लगाया जा सकता है कि डिवाइस को तुरंत रीस्टार्ट किया गया है या नहीं. ऐसा हो सकता है कि कोई गतिविधि इतनी जल्दी शुरू/बंद हो जाए कि surfaceCreated()
, onPause()
के बाद हो.
स्क्रीन को खाली करने के लिए पावर बटन पर टैप करने पर, आपको सिर्फ़ onPause()
दिखता है, surfaceDestroyed()
नहीं. सरफ़ेस चालू रहता है और रेंडरिंग जारी रहती है. अगर Choreographer इवेंट के लिए अनुरोध जारी रखा जाता है, तो आपको इवेंट मिलते रहेंगे. अगर आपकी लॉक स्क्रीन पर ओरिएंटेशन अलग है, तो डिवाइस को अनब्लैंक करने पर आपकी गतिविधि फिर से शुरू हो सकती है. इसके अलावा, स्क्रीन को पहले की तरह करने के लिए, उसी सतह पर वापस आएं.
थ्रेड का लाइफ़स्पैन, सर्फ़ेस या गतिविधि से जोड़ा जा सकता है. यह इस बात पर निर्भर करता है कि स्क्रीन खाली होने पर आपको क्या करना है. थ्रेड को गतिविधि के शुरू/बंद होने या सर्फ़ेस के बनने/मिटने पर शुरू/बंद किया जा सकता है.
गतिविधि के शुरू/बंद होने पर थ्रेड के शुरू/बंद होने की सुविधा, ऐप्लिकेशन के लाइफ़साइकल के साथ अच्छी तरह से काम करती है. आपने रेंडरर थ्रेड को onResume()
में शुरू किया है और onStop()
में बंद किया है. थ्रेड बनाते और कॉन्फ़िगर करते समय, कभी-कभी डिसप्ले पहले से मौजूद होता है और कभी-कभी नहीं होता है. उदाहरण के लिए, पावर बटन से स्क्रीन को टॉगल करने के बाद भी डिसप्ले चालू रहता है. थ्रेड में शुरू करने से पहले, आपको सर्फ़ेस बनने का इंतज़ार करना होगा. surfaceCreate()
कॉलबैक में, इसे शुरू नहीं किया जा सकता. ऐसा इसलिए, क्योंकि अगर सर्फ़ेस को फिर से नहीं बनाया गया, तो यह दोबारा ट्रिगर नहीं होगा. इसके बजाय, सर्फ़ेस की स्थिति के बारे में क्वेरी करें या उसे कैश मेमोरी में सेव करें. इसके बाद, उसे रेंडरर थ्रेड पर भेजें.
सरफ़ेस बनाने/मिटाने पर थ्रेड को शुरू/बंद करने से, बेहतर तरीके से काम होता है. ऐसा इसलिए, क्योंकि सरफ़ेस और रेंडरर एक-दूसरे से जुड़े होते हैं. सरफ़ेस बनाने के बाद थ्रेड शुरू की जाती है. इससे थ्रेड के बीच कम्यूनिकेशन से जुड़ी कुछ समस्याएं नहीं होती हैं. साथ ही, सरफ़ेस बनाने/बदलने के मैसेज फ़ॉरवर्ड किए जाते हैं. यह पुष्टि करने के लिए कि स्क्रीन के खाली होने पर रेंडरिंग बंद हो जाती है और स्क्रीन के वापस आने पर रेंडरिंग फिर से शुरू हो जाती है, Choreographer को फ़्रेम ड्रॉ कॉलबैक को इनवोक करना बंद करने के लिए कहें. onResume()
अगर रेंडरर थ्रेड चल रही है, तो यह कॉलबैक को फिर से शुरू करता है. हालांकि, अगर फ़्रेम के बीच बीते समय के आधार पर ऐनिमेशन किया जाता है, तो अगले इवेंट के आने से पहले एक बड़ा अंतर हो सकता है. इस समस्या को हल करने के लिए, साफ़ तौर पर पॉज़/फिर से शुरू करने वाले मैसेज का इस्तेमाल किया जा सकता है.
दोनों विकल्प, इस बात पर फ़ोकस करते हैं कि रेंडरर थ्रेड को कैसे कॉन्फ़िगर किया गया है और क्या वह काम कर रही है. भले ही, थ्रेड का लाइफ़स्पैन गतिविधि या प्लैटफ़ॉर्म से जुड़ा हो. एक और समस्या यह है कि गतिविधि बंद होने पर, थ्रेड से स्थिति को कैसे निकाला जाए (onStop()
या onSaveInstanceState()
में). ऐसे मामलों में, थ्रेड के लाइफ़स्पैन को गतिविधि से जोड़ना सबसे अच्छा होता है. ऐसा इसलिए, क्योंकि रेंडरर थ्रेड के जुड़ जाने के बाद, रेंडर की गई थ्रेड की स्थिति को सिंक्रनाइज़ेशन प्रिमिटिव के बिना ऐक्सेस किया जा सकता है.
GLSurfaceView
GLSurfaceView क्लास, EGL कॉन्टेक्स्ट, इंटरथ्रेड कम्यूनिकेशन, और ऐक्टिविटी लाइफ़साइकल के साथ इंटरैक्शन को मैनेज करने के लिए हेल्पर क्लास उपलब्ध कराती है. GLES का इस्तेमाल करने के लिए, GLSurfaceView का इस्तेमाल करना ज़रूरी नहीं है.
उदाहरण के लिए, GLSurfaceView रेंडरिंग के लिए एक थ्रेड बनाता है और वहां एक EGL कॉन्टेक्स्ट कॉन्फ़िगर करता है. गतिविधि रुकने पर, स्थिति अपने-आप हट जाती है. ज़्यादातर ऐप्लिकेशन को GLES के साथ GLSurfaceView का इस्तेमाल करने के लिए, EGL के बारे में कुछ भी जानने की ज़रूरत नहीं होती.
ज़्यादातर मामलों में, GLSurfaceView की मदद से GLES का इस्तेमाल करना आसान हो जाता है. कुछ मामलों में, यह समस्या पैदा कर सकता है.