परफ़ॉर्मेंस और व्यू की हैरारकी

View ऑब्जेक्ट की हैरारकी को मैनेज करने का तरीका, आपके ऐप्लिकेशन की परफ़ॉर्मेंस पर काफ़ी असर डाल सकता है. इस पेज पर यह पता लगाने का तरीका बताया गया है कि आपके व्यू की हैरारकी से आपके ऐप्लिकेशन की परफ़ॉर्मेंस पर असर पड़ रहा है या नहीं. साथ ही, इस पेज पर आने वाली समस्याओं को हल करने के लिए कुछ रणनीतियां भी बताई गई हैं.

इस पेज पर, View पर आधारित लेआउट को बेहतर बनाने पर फ़ोकस किया गया है. Jetpack Compose की परफ़ॉर्मेंस को बेहतर बनाने के बारे में जानने के लिए, Jetpack Compose की परफ़ॉर्मेंस देखें.

लेआउट और परफ़ॉर्मेंस मेज़र करना

रेंडरिंग पाइपलाइन में लेआउट और मेज़र चरण शामिल होता है. इस दौरान, सिस्टम आपके व्यू की हैरारकी में काम के आइटम को सही जगह पर रखता है. इस चरण के मेज़र वाले हिस्से से View ऑब्जेक्ट के साइज़ और सीमाएं तय होती हैं. लेआउट से यह तय होता है कि स्क्रीन पर View ऑब्जेक्ट कहां दिखाने हैं.

इन दोनों पाइपलाइन चरणों में, हर व्यू या लेआउट को प्रोसेस करने पर थोड़ी सी लागत आती है. ज़्यादातर समय, यह लागत कम होती है और इससे परफ़ॉर्मेंस पर काफ़ी कम असर पड़ता है. हालांकि, जब कोई ऐप्लिकेशन View ऑब्जेक्ट जोड़ता है या हटाता है, तो यह समय ज़्यादा हो सकता है. जैसे, जब कोई RecyclerView ऑब्जेक्ट उन्हें रीसाइकल करता है या फिर से इस्तेमाल करता है. अगर View ऑब्जेक्ट को अपनी शर्तों के मुताबिक साइज़ बदलना हो, तब भी लागत ज़्यादा हो सकती है. उदाहरण के लिए, अगर आपका ऐप्लिकेशन टेक्स्ट को रैप करने वाले View ऑब्जेक्ट पर SetText() को कॉल करता है, तो हो सकता है कि View का साइज़ बदलना पड़े.

अगर ऐसे मामलों में बहुत ज़्यादा समय लगता है, तो हो सकता है कि फ़्रेम को अनुमति वाले 16 मिलीसेकंड में रेंडर न किया जा सके. इससे फ़्रेम ड्रॉप हो सकते हैं और ऐनिमेशन में रुकावट आ सकती है.

इन ऑपरेशन को वर्क थ्रेड में नहीं भेजा जा सकता. आपके ऐप्लिकेशन को इन्हें मुख्य थ्रेड पर प्रोसेस करना होगा. इसलिए, इन्हें ऑप्टिमाइज़ करना सबसे अच्छा है, ताकि इनमें कम से कम समय लगे.

जटिल लेआउट मैनेज करना

Android लेआउट की मदद से, व्यू हैरारकी (व्यू और व्यू ग्रुप के लेआउट का क्रम) में यूज़र इंटरफ़ेस (यूआई) ऑब्जेक्ट नेस्ट किए जा सकते हैं. नेस्टिंग की वजह से लेआउट की लागत भी बढ़ सकती है. जब आपका ऐप्लिकेशन लेआउट के लिए किसी ऑब्जेक्ट को प्रोसेस करता है, तो वह लेआउट के सभी चाइल्ड पर भी यही प्रोसेस करता है.

किसी जटिल लेआउट के लिए, कभी-कभी सिर्फ़ पहली बार लेआउट का हिसाब लगाने पर शुल्क लगता है. उदाहरण के लिए, जब आपका ऐप्लिकेशन किसी RecyclerView ऑब्जेक्ट में जटिल लिस्ट आइटम को रीसाइकल करता है, तो सिस्टम को सभी ऑब्जेक्ट को लेआउट करना पड़ता है. एक और उदाहरण में, मामूली बदलाव, चेन के ज़रिए पैरंट तक तब तक पहुंच सकते हैं, जब तक वे किसी ऐसे ऑब्जेक्ट तक नहीं पहुंच जाते जिसका असर पैरंट के साइज़ पर न पड़े.

लेआउट में ज़्यादा समय लगने की एक आम वजह यह है कि View ऑब्जेक्ट की हैरारकी एक-दूसरे के अंदर नेस्ट की गई हों. नेस्ट किए गए हर लेआउट ऑब्जेक्ट के लेआउट स्टेज में लागत आती है. आपका क्रम जितना अच्छा होगा, लेआउट स्टेज को पूरा होने में उतना ही कम समय लगेगा.

हमारा सुझाव है कि RelativeLayout या LinearLayout के बजाय, ConstraintLayout बनाने के लिए, लेआउट एडिटर का इस्तेमाल करें. आम तौर पर, यह तरीका ज़्यादा असरदार होता है और इससे लेआउट को नेस्ट करने की ज़रूरत कम पड़ती है. हालांकि, FrameLayout का इस्तेमाल करके बनाए जा सकने वाले आसान लेआउट के लिए, हमारा सुझाव है कि आप FrameLayout का इस्तेमाल करें.

अगर RelativeLayout क्लास का इस्तेमाल किया जा रहा है, तो नेस्ट किए गए और बिना वेट वाले LinearLayout व्यू का इस्तेमाल करके, कम लागत में वही इफ़ेक्ट पाया जा सकता है. हालांकि, अगर नेस्ट किए गए और अहमियत वाले LinearLayout व्यू का इस्तेमाल किया जा रहा है, तो लेआउट की लागत बहुत ज़्यादा होती है. इसकी वजह यह है कि इसके लिए, एक से ज़्यादा लेआउट पास की ज़रूरत होती है. इस बारे में अगले सेक्शन में बताया गया है.

हमारा सुझाव है कि आप ListView के बजाय RecyclerView का इस्तेमाल करें. ऐसा इसलिए, क्योंकि यह सूची के अलग-अलग आइटम के लेआउट को रीसाइकल कर सकता है. इससे, यह ज़्यादा असरदार होता है और स्क्रोल करने की परफ़ॉर्मेंस भी बेहतर होती है.

दोहरा टैक्सेशन

आम तौर पर, फ़्रेमवर्क एक ही पास में लेआउट या मेज़र स्टेज को लागू करता है. हालांकि, कुछ जटिल लेआउट केस के साथ, फ़्रेमवर्क को हैरारकी के उन हिस्सों में कई बार दोहराना पड़ सकता है जिन्हें ठीक करने के लिए एक से ज़्यादा पास की ज़रूरत होती है, ताकि एलिमेंट की पोज़िशन तय हो सके. एक से ज़्यादा लेआउट और मेज़रमेंट का इटरेशन करने की ज़रूरत पड़ने पर, इसे डबल टैक्सेशन कहा जाता है.

उदाहरण के लिए, जब RelativeLayout कंटेनर का इस्तेमाल किया जाता है, जिससे View ऑब्जेक्ट को, View ऑब्जेक्ट की पोज़िशन के हिसाब से जगह पर सेट किया जा सकता है, तो फ़्रेमवर्क इस क्रम में काम करता है:

  1. लेआउट और मेज़रमेंट पास लागू करता है. इस दौरान, फ़्रेमवर्क हर चाइल्ड के अनुरोध के आधार पर हर चाइल्ड ऑब्जेक्ट की पोज़िशन और साइज़ का हिसाब लगाता है.
  2. इस डेटा का इस्तेमाल करके, ऑब्जेक्ट के वज़न को ध्यान में रखते हुए, मिलते-जुलते व्यू की सही स्थिति का पता लगाया जाता है.
  3. ऑब्जेक्ट की पोज़िशन तय करने के लिए, दूसरा लेआउट पास करता है.
  4. रेंडरिंग की प्रोसेस के अगले चरण पर ले जाता है.

आपके व्यू हैरारकी (व्यू और व्यू ग्रुप के लेआउट का क्रम) में जितने ज़्यादा लेवल होंगे, परफ़ॉर्मेंस पर जुर्माना लगने की संभावना उतनी ही ज़्यादा होगी.

जैसा कि पहले बताया गया था, ConstraintLayout आम तौर पर FrameLayout को छोड़कर, अन्य लेआउट की तुलना में ज़्यादा असरदार होता है. इसमें एक से ज़्यादा लेआउट पास होने की संभावना कम होती है. साथ ही, कई मामलों में लेआउट को नेस्ट करने की ज़रूरत नहीं होती.

RelativeLayout के अलावा, दूसरे कंटेनर का इस्तेमाल करने पर भी दो बार टैक्स लग सकता है. जैसे:

  • LinearLayout व्यू को हॉरिज़ॉन्टल बनाने पर, दो बार लेआउट और मेज़रमेंट पास हो सकता है. अगर आपने measureWithLargestChild जोड़ा है, तो वर्टिकल ओरिएंटेशन में भी डबल लेआउट-और-मेज़र पास हो सकता है. ऐसे में, ऑब्जेक्ट के सही साइज़ को हल करने के लिए, फ़्रेमवर्क को दूसरा पास करना पड़ सकता है.
  • GridLayout में भी रिलेटिव पोज़िशनिंग की सुविधा होती है. हालांकि, आम तौर पर यह चाइल्ड व्यू के बीच पोज़िशन के रिलेशनशिप को पहले से प्रोसेस करके, डबल टैक्सेशन से बचता है. हालांकि, अगर लेआउट में वज़न का इस्तेमाल किया जाता है या Gravity क्लास के साथ भर दिया जाता है, तो पहले से प्रोसेस करने का फ़ायदा नहीं मिलता. साथ ही, अगर कंटेनर RelativeLayout है, तो फ़्रेमवर्क को कई पास करने पड़ सकते हैं.

यह ज़रूरी नहीं है कि एक से ज़्यादा लेआउट और मेज़रमेंट पास का इस्तेमाल करने से, परफ़ॉर्मेंस पर असर पड़ता हो. हालांकि, अगर वे गलत जगह पर हैं, तो वे बोझ बन सकते हैं. इन स्थितियों में सावधानी बरतें, जब आपके कंटेनर पर इनमें से कोई एक शर्त लागू हो:

  • यह आपकी व्यू हैरारकी में रूट एलिमेंट होता है.
  • इसके नीचे, डीप व्यू हैरारकी है.
  • स्क्रीन पर कई तरीकों से जानकारी अपने-आप भरी जा सकती है. यह ठीक वैसे ही होता है जैसे ListView ऑब्जेक्ट में बच्चों की जानकारी दिखती है.

व्यू हैरारकी से जुड़ी समस्याओं का पता लगाना

लेआउट की परफ़ॉर्मेंस एक जटिल समस्या है, जिसमें कई पहलू शामिल हैं. नीचे दिए गए टूल की मदद से, यह पता लगाया जा सकता है कि परफ़ॉर्मेंस में रुकावटें कहां आ रही हैं. कुछ टूल, सटीक जानकारी नहीं देते, लेकिन मददगार सुझाव दे सकते हैं.

Perfetto

Perfetto एक ऐसा टूल है जो परफ़ॉर्मेंस के बारे में डेटा देता है. Perfetto यूज़र इंटरफ़ेस में Android ट्रैक खोले जा सकते हैं.

प्रोफ़ाइल GPU रेंडरिंग

डिवाइस पर मौजूद जीपीयू रेंडरिंग की प्रोफ़ाइल टूल, Android 6.0 (एपीआई लेवल 23) और उसके बाद के वर्शन वाले डिवाइसों पर उपलब्ध है. इससे, आपको परफ़ॉर्मेंस से जुड़ी समस्याओं के बारे में सटीक जानकारी मिल सकती है. इस टूल की मदद से, यह देखा जा सकता है कि रेंडरिंग के हर फ़्रेम के लिए, लेआउट और मेज़र करने वाले चरण में कितना समय लग रहा है. इस डेटा की मदद से, रनटाइम परफ़ॉर्मेंस से जुड़ी समस्याओं का पता लगाया जा सकता है. साथ ही, यह भी तय किया जा सकता है कि आपको लेआउट और मेज़र से जुड़ी किन समस्याओं को ठीक करना है.

प्रोफ़ाइल जीपीयू रेंडरिंग, कैप्चर किए गए डेटा को ग्राफ़िक के तौर पर दिखाती है. इसमें लेआउट के समय को दिखाने के लिए, नीले रंग का इस्तेमाल किया जाता है. इस टूल का इस्तेमाल करने के तरीके के बारे में ज़्यादा जानकारी के लिए, प्रोफ़ाइल जीपीयू रेंडरिंग स्पीड देखें.

Lint

Android Studio के Lint टूल की मदद से, व्यू के क्रम में मौजूद गड़बड़ियों का पता लगाया जा सकता है. इस टूल का इस्तेमाल करने के लिए, विश्लेषण करें > कोड की जांच करें को चुनें, जैसा कि पहला इमेज में दिखाया गया है.

पहली इमेज. Android Studio में, कोड की जांच करें को चुनें.

अलग-अलग लेआउट आइटम की जानकारी, Android > Lint > परफ़ॉर्मेंस में दिखती है. ज़्यादा जानकारी के लिए, हर आइटम पर क्लिक करके उसे बड़ा करें और स्क्रीन की दाईं ओर मौजूद पैनल में ज़्यादा जानकारी दिखाएं. दूसरी इमेज में पूरी जानकारी देने का उदाहरण दिखाया गया है.

दूसरी इमेज. Lint टूल की मदद से पहचानी गई खास समस्याओं के बारे में जानकारी देखना.

किसी आइटम पर क्लिक करने से, दाईं ओर मौजूद पैनल में उस आइटम से जुड़ी समस्याएं दिखती हैं.

इस सेक्शन में मौजूद खास विषयों और समस्याओं के बारे में ज़्यादा जानने के लिए, Lint दस्तावेज़ देखें.

लेआउट इंस्पेक्टर

Android Studio का लेआउट इंस्पेक्टर टूल, आपके ऐप्लिकेशन की व्यू हैरारकी को विज़ुअल के तौर पर दिखाता है. यह आपके ऐप्लिकेशन की हैरारकी में नेविगेट करने का एक अच्छा तरीका है. इससे किसी खास व्यू की पैरंट चेन को साफ़ तौर पर विज़ुअल तौर पर दिखाया जाता है. साथ ही, आपको उन लेआउट की जांच करने की सुविधा मिलती है जिन्हें आपका ऐप्लिकेशन बनाता है.

लेआउट इंस्पेक्टर के व्यू से, डबल टैक्सेशन की वजह से होने वाली परफ़ॉर्मेंस से जुड़ी समस्याओं का पता लगाने में भी मदद मिल सकती है. इसकी मदद से, नेस्ट किए गए लेआउट की डीप चेन या नेस्ट किए गए बहुत सारे चाइल्ड एलिमेंट वाले लेआउट एरिया की पहचान की जा सकती है. ये एरिया, परफ़ॉर्मेंस की लागत का सोर्स हो सकते हैं. ऐसे मामलों में, लेआउट और मेज़र करने के चरणों में ज़्यादा समय लग सकता है और परफ़ॉर्मेंस से जुड़ी समस्याएं हो सकती हैं.

ज़्यादा जानकारी के लिए, लेआउट इंस्पेक्टर और लेआउट की पुष्टि करने की सुविधा का इस्तेमाल करके, अपने लेआउट को डीबग करना लेख पढ़ें.

व्यू हैरारकी से जुड़ी समस्याएं हल करना

व्यू की हैरारकी से जुड़ी परफ़ॉर्मेंस की समस्याओं को हल करने का बुनियादी कॉन्सेप्ट, व्यवहार में मुश्किल हो सकता है. व्यू हैरारकी की वजह से परफ़ॉर्मेंस पर लगने वाले जुर्माने से बचने के लिए, व्यू हैरारकी को फ़्लैट करें और डबल टैक्स को कम करें. इस सेक्शन में, इन लक्ष्यों को हासिल करने के लिए रणनीतियों के बारे में बताया गया है.

नेस्ट किए गए ऐसे लेआउट हटाना जो काम के नहीं हैं

ConstraintLayout एक Jetpack लाइब्रेरी है. इसमें लेआउट में व्यू को पोज़िशन करने के लिए, कई तरह के अलग-अलग तरीके मौजूद हैं. इससे, एक ConstaintLayout को नेस्ट करने की ज़रूरत कम हो जाती है. साथ ही, व्यू की हैरारकी को फ़्लैट करने में भी मदद मिलती है. आम तौर पर, अन्य लेआउट टाइप के मुकाबले ConstraintLayout का इस्तेमाल करके हैरारकी को फ़्लैट करना आसान होता है.

डेवलपर अक्सर ज़रूरत से ज़्यादा नेस्ट किए गए लेआउट का इस्तेमाल करते हैं. उदाहरण के लिए, किसी RelativeLayout कंटेनर में एक चाइल्ड हो सकता है, जो कि RelativeLayout कंटेनर भी हो सकता है. यह नेस्टिंग गैर-ज़रूरी है और व्यू हैरारकी में गैर-ज़रूरी लागत जोड़ता है. Lint इस समस्या को फ़्लैग कर सकता है, ताकि डीबग करने में कम समय लगे.

मर्ज करें या शामिल करें

<include> टैग, नेस्ट किए गए ग़ैर-ज़रूरी लेआउट की सबसे सामान्य वजह है. उदाहरण के लिए, बार-बार इस्तेमाल किए जा सकने वाले लेआउट को इस तरह से तय किया जा सकता है:

<LinearLayout>
    <!-- some stuff here -->
</LinearLayout>

इसके बाद, पैरंट कंटेनर में यह आइटम जोड़ने के लिए, <include> टैग जोड़ा जा सकता है:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/app_bg"
    android:gravity="center_horizontal">

    <include layout="@layout/titlebar"/>

    <TextView android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:text="@string/hello"
              android:padding="10dp" />

    ...

</LinearLayout>

पहले लेआउट को दूसरे लेआउट में शामिल करने की ज़रूरत नहीं है.

<merge> टैग की मदद से, इस समस्या से बचा जा सकता है. इस टैग के बारे में जानकारी के लिए, <merge> टैग इस्तेमाल करना देखें.

सस्ता लेआउट अपनाएं

ऐसा हो सकता है कि आप अपने मौजूदा लेआउट स्कीम में बदलाव न कर पाएं, ताकि उसमें ग़ैर-ज़रूरी लेआउट न हों. कुछ मामलों में, पूरी तरह से अलग लेआउट टाइप पर स्विच करके, हैरारकी को फ़्लैट करना ही एकमात्र समाधान हो सकता है.

उदाहरण के लिए, आपको यह दिख सकता है कि TableLayout, कई पोज़िशनल डिपेंडेंसी वाले ज़्यादा जटिल लेआउट की तरह ही काम करता है. Jetpack लाइब्रेरी ConstraintLayout, RelativeLayout जैसी ही फ़ंक्शनलिटी उपलब्ध कराती है. साथ ही, इसमें ज़्यादा सुविधाएं भी होती हैं, जिनकी मदद से फ़्लैटर और ज़्यादा असरदार लेआउट बनाए जा सकते हैं.