इमेज के साथ काम करते समय, अगर सावधानी न बरती जाए, तो परफ़ॉर्मेंस से जुड़ी समस्याएं आ सकती हैं. JPG या PNG जैसे कंप्रेस किए गए फ़ॉर्मैट में मौजूद छोटा ग्राफ़िक भी, डिकोड होने के बाद एक बड़े बिट मैप में बदल सकता है. अगर ग्राफ़िक का इस्तेमाल सही तरीके से नहीं किया जाता है, तो आपको मेमोरी से जुड़ी समस्याएं आ सकती हैं. इससे आपके ऐप्लिकेशन और डिवाइस पर मौजूद अन्य ऐप्लिकेशन की परफ़ॉर्मेंस पर असर पड़ सकता है. यह पक्का करने के लिए कि आपका ऐप्लिकेशन बेहतर तरीके से काम करे, यहां दिए गए सबसे सही तरीके अपनाएं.
इमेज लोड करने वाली लाइब्रेरी का इस्तेमाल करना
इमेज लोड करने वाली लाइब्रेरी का इस्तेमाल करके, अपने ऐप्लिकेशन की परफ़ॉर्मेंस को बेहतर बनाया जा सकता है. जैसे, Kotlin-फ़र्स्ट प्रोजेक्ट के लिए Coil या Java प्रोजेक्ट के लिए Glide. ये लाइब्रेरी, आपके ऐप्लिकेशन की मेमोरी के इस्तेमाल को कम करती हैं. इसके लिए, वे इमेज को कैश मेमोरी में सेव करती हैं, ज़रूरत पड़ने पर ग्राफ़िक को डाउनसैंपल करती हैं, और ग्राफ़िक ऑब्जेक्ट को रीसाइकल करती हैं.
इमेज को डाउनसैंपल करना
अपनी ज़रूरत के हिसाब से सही इमेज साइज़ का इस्तेमाल करें. आपको किसी छोटे कंटेनर (जैसे कि थंबनेल) में बड़ी और हाई रिज़ॉल्यूशन वाली इमेज लोड करने से बचना चाहिए. इसके बजाय, इमेज को मेमोरी में डिकोड करने से पहले, डाउनसैंपल करने की प्रोसेस का इस्तेमाल करके इमेज का साइज़ छोटा करें.
क्लाइंट-साइड डाउनसैंपलिंग
Coil और Glide जैसी इमेज लोड करने वाली लाइब्रेरी, डाउनसैंपलिंग की प्रोसेस को अपने-आप मैनेज करती हैं. ImageLoader (Coil के लिए) या DownsampleStrategy (Glide के लिए) का इस्तेमाल करके, डाउनसैंपलिंग की रणनीतियों को कॉन्फ़िगर किया जा सकता है. अगर बिटमैप को मैन्युअल तरीके से मैनेज किया जा रहा है, तो छोटे वर्शन को डिकोड करने के लिए, inSampleSize का इस्तेमाल किया जा सकता है. इसे सुरक्षित तरीके से करने के लिए, आपको सबसे पहले inJustDecodeBounds को true पर सेट करना होगा, ताकि मेमोरी को ऐलोकेट किए बिना इमेज के डाइमेंशन को पढ़ा जा सके. इसके बाद, सैंपल का साइज़ कैलकुलेट करें, inSampleSize को उस वैल्यू पर सेट करें, inJustDecodeBounds को false पर सेट करें, और फिर इमेज को डिकोड करें.
सर्वर-साइड पर साइज़ बदलने की सुविधा को प्राथमिकता दें
जहां संभव हो, सीधे अपने बैकएंड सर्वर से इमेज के सटीक डाइमेंशन का अनुरोध करें. इससे नेटवर्क का इस्तेमाल और डिस्क की कैश मेमोरी का फ़ुटप्रिंट कम होता है. साथ ही, डिवाइस पर इमेज का साइज़ बदलने के लिए मेमोरी ओवरहेड से बचकर, मेमोरी का इस्तेमाल कम किया जा सकता है.
लाइब्रेरी को इस तरह कॉन्फ़िगर किया जा सकता है कि वे इमेज यूआरएल में, टारगेट व्यू के साइज़ को डाइनैमिक तौर पर जोड़ सकें. उदाहरण के लिए, Coil कस्टम इंटरसेप्टर का इस्तेमाल करके ऐसा करने की अनुमति देता है. वहीं, Glide कस्टम मॉडल लोडर (जैसे कि BaseGlideUrlLoader) का इस्तेमाल करके ऐसा करने की अनुमति देता है.
लेआउट के साइज़ को सीमित न रखने से बचें
इमेज लोड करने वाले टूल, क्लाइंट-साइड या सर्वर-साइड पर इमेज को डाउनसैंपल करते हैं. इसके लिए, उन्हें अनुरोध को पूरा करने से पहले, इमेज के टारगेट साइज़ की जानकारी होनी चाहिए.
रिमोट इमेज लोड करने वाले कंपोज़ेबल पर, wrapContentSize का इस्तेमाल करने या डाइमेंशन को बिना किसी पाबंदी के छोड़ने से बचें. अगर ये लाइब्रेरी, टारगेट बाउंड का अनुमान नहीं लगा पाती हैं, तो वे ओरिजनल फ़ुल-साइज़ इमेज को लोड करती हैं.
इसकी वजह से, ज़रूरत से ज़्यादा बड़ी इमेज लोड हो सकती है. इससे मेमोरी का इस्तेमाल और इंतज़ार का समय बढ़ सकता है.
इसके बजाय, इमेज कंपोज़ेबल पर साफ़ तौर पर डाइमेंशन सेट करें (उदाहरण के लिए, Modifier.size का इस्तेमाल करके) या आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात) तय करें. इससे लेआउट इंजन को पहले ही सटीक पिक्सल टारगेट का पता चल जाता है. इसके बाद, इमेज लोडर इसका इस्तेमाल करके, सही साइज़ वाली ऐसेट का अनुरोध कर सकता है और उसे डिकोड कर सकता है.
अलग-अलग स्क्रीन साइज़ के लिए वैकल्पिक संसाधन उपलब्ध कराना
अगर आपके ऐप्लिकेशन में इमेज शामिल हैं, तो अलग-अलग डिवाइस रिज़ॉल्यूशन के लिए अलग-अलग साइज़ की ऐसेट उपलब्ध कराएं. इससे डिवाइसों पर आपके ऐप्लिकेशन का डाउनलोड साइज़ कम करने में मदद मिल सकती है. साथ ही, परफ़ॉर्मेंस को बेहतर बनाया जा सकता है, क्योंकि यह कम रिज़ॉल्यूशन वाले डिवाइस पर कम रिज़ॉल्यूशन वाली इमेज लोड करेगा. अलग-अलग डिवाइस साइज़ के लिए वैकल्पिक बिट मैप उपलब्ध कराने के बारे में ज़्यादा जानकारी पाने के लिए, वैकल्पिक बिट मैप का दस्तावेज़ देखें.
सीधे पैडिंग लागू न करें
कभी-कभी आपको किसी इमेज में पैडिंग जोड़ने की ज़रूरत पड़ सकती है. उदाहरण के लिए, हो सकता है कि आप लेटरबॉक्सिंग के लिए, इमेज के चारों ओर पारदर्शी बॉर्डर लगाना चाहें.
ऐसे मामलों में, इमेज के डाइमेंशन में बदलाव करके, सीधे इमेज में पैडिंग न जोड़ें. इसके बजाय, इमेज के डाइमेंशन को पहले जैसा ही रहने दें और InsetDrawable का इस्तेमाल करके, स्क्रीन पर इमेज की जगह में बदलाव करें.
इसके अलावा, इमेज को होल्ड करने वाले कंपोज़ेबल या व्यू में पैडिंग जोड़ी जा सकती है.
Pixel का डेटा एक्सपोर्ट करने के लिए, सही फ़ाइल फ़ॉर्मैट चुनना
सही पिक्सल फ़ॉर्मैट चुनकर, मेमोरी और क्वालिटी को बैलेंस करें. RGB_565 का इस्तेमाल तब करें, जब आपको पारदर्शिता की ज़रूरत न हो. यह फ़ॉर्मैट, डिफ़ॉल्ट ARGB_8888 फ़ॉर्मैट की तुलना में आधी मेमोरी का इस्तेमाल करता है.
Glide में, DecodeFormat का इस्तेमाल करके इसे कॉन्फ़िगर किया जा सकता है. Coil में, bitmapConfig प्रॉपर्टी का इस्तेमाल किया जा सकता है.
जहां तक हो सके, वेक्टर का इस्तेमाल करें
ज्यामितीय आकृतियों से बनी इमेज के लिए, वेक्टर ग्राफ़िक का साइज़ बिटमैप से काफ़ी छोटा होता है. साथ ही, यह किसी भी डिसप्ले डेंसिटी के लिए आसानी से स्केल हो जाता है. ज़रूरत पड़ने पर, ग्राफ़िक दिखाने के लिए ShapeDrawable जैसे एलिमेंट का इस्तेमाल करें.
जब भी संभव हो, बिटमैप को रिलीज़ करें और फिर से इस्तेमाल करें
बड़ी ग्राफ़िक फ़ाइलें, ज़्यादा मेमोरी ले सकती हैं. इनके असर को कम करने के लिए, आपको जब भी हो सके, ग्राफ़िक ऑब्जेक्ट को रिलीज़ करना चाहिए या फिर से इस्तेमाल करना चाहिए.
अगर इमेज लोड करने वाली लाइब्रेरी का इस्तेमाल किया जा रहा है, तो जब बिटमैप की ज़रूरत न हो, तब उन्हें लाइब्रेरी के मैनेज किए गए पूल में रिलीज़ करना न भूलें. ज़रूरत पड़ने पर, लाइब्रेरी ऑब्जेक्ट का फिर से इस्तेमाल कर सकती है. साथ ही, आने वाले समय में इस्तेमाल करने के लिए मेमोरी बफ़र उपलब्ध रखती है.
अगर ग्राफ़िक को मैन्युअल तरीके से मैनेज किया जा रहा है, तो काम पूरा होने पर बिटमैप को रिलीज़ कर देना चाहिए. इसके लिए, Bitmap.recycle को कॉल करें और Bitmap रेफ़रंस को तुरंत खारिज कर दें. इसके लिए, गार्बेज कलेक्शन पर भरोसा न करें.
अन्य सुझाव और तरकीबें
इस सेक्शन में, ग्राफ़िक को हैंडल करते समय अपने ऐप्लिकेशन की परफ़ॉर्मेंस को बेहतर बनाने के कुछ अन्य तरीके बताए गए हैं.
अपनी AAB/APK फ़ाइल के साथ बड़ी इमेज पैकेज न करें
ऐप्लिकेशन के डाउनलोड साइज़ के बड़े होने की एक मुख्य वजह, एएबी या APK फ़ाइल में मौजूद ग्राफ़िक्स होते हैं. APK ऐनालाइज़र टूल का इस्तेमाल करके पक्का करें कि आपने ज़रूरत से ज़्यादा बड़ी इमेज फ़ाइलें पैकेज नहीं की हैं. इमेज का साइज़ कम करें या उन्हें किसी सर्वर पर सेव करें और ज़रूरत पड़ने पर ही डाउनलोड करें.
बेकार बिटमैप ढूंढना
अगर आपके पास एक ही इमेज की कई कॉपी हैं, तो इससे मेमोरी बर्बाद होती है. Android Studio के प्रोफ़ाइलर का इस्तेमाल करके, ग़ैर-ज़रूरी ग्राफ़िक की पहचान की जा सकती है. हीप डंप कैप्चर करने के लिए, हीप डंप ऐनलाइज़र का इस्तेमाल करें. साथ ही, डुप्लीकेट बिटमैप सेटिंग चुनकर, नतीजों को फ़िल्टर करें.
ImageBitmap का इस्तेमाल करते समय, ड्रॉ करने से पहले prepareToDraw को कॉल करें
ImageBitmap का इस्तेमाल करते समय, जीपीयू पर टेक्सचर अपलोड करने की प्रोसेस शुरू करने के लिए, उसे ड्रॉ करने से पहले ImageBitmap#prepareToDraw() को कॉल करें. इससे जीपीयू को टेक्सचर तैयार करने और स्क्रीन पर विज़ुअल दिखाने की परफ़ॉर्मेंस को बेहतर बनाने में मदद मिलती है. इमेज लोड करने वाली ज़्यादातर लाइब्रेरी, पहले से ही इस ऑप्टिमाइज़ेशन का इस्तेमाल करती हैं. हालांकि, अगर ImageBitmap क्लास के साथ खुद काम किया जा रहा है, तो इस बात का ध्यान रखना ज़रूरी है.
Painter के बजाय, अपने कंपोज़ेबल में पैरामीटर के तौर पर Int DrawableRes या यूआरएल पास करें
इमेज के साथ काम करने की जटिलताओं की वजह से, Painter एपीआई को साफ़ तौर पर @Stable एनोटेशन के साथ स्टेबल के तौर पर मार्क नहीं किया गया है. उदाहरण के लिए, Bitmaps के लिए बराबर फ़ंक्शन लिखने में ज़्यादा कंप्यूटेशनल खर्च आएगा. अनस्टेबल क्लास की वजह से, ग़ैर-ज़रूरी रीकंपोज़िशन हो सकते हैं. ऐसा इसलिए होता है, क्योंकि कंपाइलर आसानी से यह अनुमान नहीं लगा पाता कि डेटा में बदलाव हुआ है या नहीं.
इसलिए, हमारा सुझाव है कि आप अपने कंपोज़ेबल में पैरामीटर के तौर पर Painter पास करने के बजाय, यूआरएल या ड्रॉ करने लायक संसाधन आईडी को पैरामीटर के तौर पर पास करें.
// Prefer this:
@Composable
fun MyImage(url: String) {
}
// Over this:
@Composable
fun MyImage(painter: Painter) {
}
आपके लिए सुझाव
- ध्यान दें: JavaScript बंद होने पर, लिंक टेक्स्ट दिखता है
- ImageBitmap बनाम ImageVector {:#bitmap-vs-vector}
- Compose में यूज़र इंटरफ़ेस (यूआई) की स्थिति सेव करना
- Jetpack Compose के फ़ेज़