ऐप्लिकेशन को ऑप्टिमाइज़ करने के लिए, आपको ऐसी लाइब्रेरी का इस्तेमाल करना होगा जो Android के ऑप्टिमाइज़ेशन के साथ काम करती हों. अगर किसी लाइब्रेरी को Android के ऑप्टिमाइज़ेशन के लिए कॉन्फ़िगर नहीं किया गया है, तो हो सकता है कि वह Android ऐप्लिकेशन के लिए सही न हो. उदाहरण के लिए, अगर वह उससे जुड़े कीप नियमों को बंडल किए बिना रिफ़्लेक्शन का इस्तेमाल करती है. इस पेज पर बताया गया है कि कुछ लाइब्रेरी, ऐप्लिकेशन को ऑप्टिमाइज़ करने के लिए बेहतर क्यों होती हैं. साथ ही, आपको चुनने में मदद करने के लिए सामान्य सलाह भी दी गई है.
लाइब्रेरी चुनते समय सामान्य सलाह
इन सलाहों का इस्तेमाल करके, यह पक्का करें कि आपकी लाइब्रेरी, ऐप्लिकेशन को ऑप्टिमाइज़ करने के साथ काम करती हैं.
रिफ़्लेक्शन के बजाय कोड जनरेशन का इस्तेमाल करना
ऐसी लाइब्रेरी चुनें जो कोड जनरेशन (codegen) रिफ़्लेक्शन के बजाय इस्तेमाल करती हैं. कोड जनरेशन की मदद से, ऑप्टिमाइज़र यह तय कर सकता है कि रनटाइम में कौनसा कोड इस्तेमाल किया जाता है और कौनसा कोड हटाया जा सकता है. यह बताना मुश्किल हो सकता है कि कोई लाइब्रेरी, कोड जनरेशन या रिफ़्लेक्शन का इस्तेमाल करती है या नहीं. हालांकि, इसके कुछ संकेत होते हैं. ज़्यादा जानकारी के लिए, सलाहें देखें.
कोड जनरेशन बनाम रिफ़्लेक्शन के बारे में ज़्यादा जानने के लिए, लाइब्रेरी तैयार करने वालों के लिए ऑप्टिमाइज़ेशन लेख पढ़ें.
रिफ़्लेक्शन के इस्तेमाल की जांच करना (ऐडवांस)
लाइब्रेरी के कोड की जांच करके, यह पता लगाया जा सकता है कि वह रिफ़्लेक्शन का इस्तेमाल करती है या नहीं. अगर लाइब्रेरी, रिफ़्लेक्शन का इस्तेमाल करती है, तो देखें कि वह उससे जुड़े कीप नियम उपलब्ध कराती है या नहीं. अगर कोई लाइब्रेरी ये काम करती है, तो हो सकता है कि वह रिफ़्लेक्शन का इस्तेमाल करती हो:
kotlin.reflectयाjava.lang.reflectपैकेज से क्लास या तरीकों का इस्तेमाल करती है.Class.forNameयाclassLoader.getClassफ़ंक्शन का इस्तेमाल करती है.- रनटाइम में एनोटेशन पढ़ती है. उदाहरण के लिए, अगर वह एनोटेशन की वैल्यू
सेव करती है
val value = myClass.getAnnotation()याval value = myMethod.getAnnotation()का इस्तेमाल करके और फिरvalueके साथ कुछ करती है. किसी तरीके के नाम को स्ट्रिंग के तौर पर इस्तेमाल करके, तरीकों को कॉल करती है. जैसे, यहां दिए गए उदाहरण में:
// Calls the private `processData` API with reflection myObject.javaClass.getMethod("processData", DataType::class.java) ?.invoke(myObject, data)
ऑप्टिमाइज़ेशन से जुड़ी समस्याओं की जांच करना
नई लाइब्रेरी इस्तेमाल करने से पहले, लाइब्रेरी के इश्यू ट्रैकर और ऑनलाइन चर्चाओं को देखें. इससे यह पता चलेगा कि मिनीफ़िकेशन या ऐप्लिकेशन को ऑप्टिमाइज़ करने के लिए कॉन्फ़िगर करने से जुड़ी कोई समस्या है या नहीं. अगर कोई समस्या है, तो आपको उस लाइब्रेरी के विकल्पों को देखना चाहिए. इन बातों का ध्यान रखें:
- AndroidX लाइब्रेरी और Hilt जैसी लाइब्रेरी, ऐप्लिकेशन को ऑप्टिमाइज़ करने के साथ अच्छी तरह काम करती हैं. ऐसा इसलिए, क्योंकि वे रिफ़्लेक्शन के बजाय ज़्यादातर कोड जनरेशन का इस्तेमाल करती हैं. जब वे रिफ़्लेक्शन का इस्तेमाल करती हैं, तो वे सिर्फ़ ज़रूरी कोड को बनाए रखने के लिए, कम से कम कीप नियम उपलब्ध कराती हैं.
- सीरियलाइज़ेशन लाइब्रेरी, ऑब्जेक्ट को इंस्टैंशिएट या सीरियलाइज़ करते समय, बॉयलरप्लेट कोड से बचने के लिए अक्सर रिफ़्लेक्शन का इस्तेमाल करती हैं. रिफ़्लेक्शन पर आधारित तरीकों (जैसे, JSON के लिए Gson) के बजाय, ऐसी लाइब्रेरी देखें जो इन समस्याओं से बचने के लिए कोड जनरेशन का इस्तेमाल करती हैं. उदाहरण के लिए, Kotlin Serialization {:.external} या कोड जनरेशन के साथ Moshi का इस्तेमाल करें.
- अगर हो सके, तो ऐसी लाइब्रेरी इस्तेमाल न करें जिनमें पैकेज-वाइड कीप नियम शामिल हों. पैकेज-वाइड कीप नियम, गड़बड़ियों को ठीक करने में मदद कर सकते हैं. हालांकि, ब्रॉड कीप नियमों को समय के साथ बेहतर बनाया जाना चाहिए, ताकि सिर्फ़ ज़रूरी कोड को बनाए रखा जा सके. ज़्यादा जानकारी के लिए, धीरे-धीरे ऑप्टिमाइज़ेशन लागू करना लेख पढ़ें.
- तीसरे पक्ष की लाइब्रेरी का इस्तेमाल करने वाला ऐप्लिकेशन पब्लिश करने से पहले, R8 कॉन्फ़िगरेशन एनलाइज़र का इस्तेमाल करके, उपलब्ध कराए गए कीप नियमों की ऑडिट करें. रिपोर्ट की समीक्षा करके, आप यह पुष्टि कर सकते हैं कि लाइब्रेरी के कीप नियम बहुत ब्रॉड तो नहीं हैं. अगर ऐसा है, तो R8 आपके कोड बेस पर अहम ऑप्टिमाइज़ेशन नहीं कर पाएगा. इस जांच से यह पक्का होता है कि चुनी गई लाइब्रेरी, आपके ऐप्लिकेशन के परफ़ॉर्मेंस के लक्ष्यों के मुताबिक हैं और उनसे कॉन्फ़िगरेशन में ज़रूरत से ज़्यादा डेटा नहीं जुड़ता है.
- लाइब्रेरी के लिए, आपको दस्तावेज़ से कीप नियमों को कॉपी करके, अपने प्रोजेक्ट की किसी फ़ाइल में चिपकाने की ज़रूरत नहीं होनी चाहिए. खासकर, पैकेज-वाइड कीप नियमों के लिए. लंबे समय में, इन नियमों की वजह से ऐप्लिकेशन डेवलपर को रखरखाव में परेशानी हो सकती है. साथ ही, इन्हें समय के साथ ऑप्टिमाइज़ और बदला नहीं जा सकता.
नई लाइब्रेरी जोड़ने के बाद, ऑप्टिमाइज़ेशन की सुविधा चालू करना
नई लाइब्रेरी जोड़ने के बाद, ऑप्टिमाइज़ेशन की सुविधा चालू करें और देखें कि कोई गड़बड़ी तो नहीं है. अगर कोई गड़बड़ी है, तो उस लाइब्रेरी के विकल्प देखें या कीप नियम लिखें. अगर कोई लाइब्रेरी, ऑप्टिमाइज़ेशन के साथ काम नहीं करती है, तो उस लाइब्रेरी के साथ कोई बग फ़ाइल करें.
खराब कीप नियमों को फ़िल्टर करना (ऐडवांस)
कीप नियम, ऐडिटिव होते हैं. इसका मतलब है कि लाइब्रेरी की डिपेंडेंसी में शामिल कुछ नियमों को हटाया नहीं जा सकता. साथ ही, ये आपके ऐप्लिकेशन के अन्य हिस्सों के कंपाइलेशन पर असर डाल सकते हैं. उदाहरण के लिए, अगर किसी लाइब्रेरी में कोड ऑप्टिमाइज़ेशन को बंद करने का कोई नियम शामिल है, तो वह नियम आपके पूरे प्रोजेक्ट के लिए ऑप्टिमाइज़ेशन को बंद कर देता है.
आपको ऐसी लाइब्रेरी इस्तेमाल नहीं करनी चाहिए जिनमें ऐसे कीप नियम हों जो ऐसे कोड को बनाए रखते हैं जिसे हटा दिया जाना चाहिए. हालांकि, अगर आपको उनका इस्तेमाल करना ही है, तो यहां दिए गए कोड के मुताबिक, नियमों को फ़िल्टर किया जा सकता है:
// If you're using AGP 8.4 and higher
buildTypes {
release {
optimization.keepRules {
it.ignoreFrom("com.somelibrary:somelibrary")
}
}
}
// If you're using AGP 7.3-8.3
buildTypes {
release {
optimization.keepRules {
it.ignoreExternalDependencies("com.somelibrary:somelibrary")
}
}
}
केस स्टडी: ऑप्टिमाइज़ेशन के साथ Gson क्यों काम नहीं करता
Gson, सीरियलाइज़ेशन लाइब्रेरी है. यह अक्सर ऐप्लिकेशन को ऑप्टिमाइज़ करने में समस्याएं पैदा करती है, क्योंकि यह रिफ़्लेक्शन का ज़्यादा इस्तेमाल करती है. यहां दिए गए कोड स्निपेट में दिखाया गया है कि Gson का इस्तेमाल आम तौर पर कैसे किया जाता है. इससे रनटाइम में क्रैश हो सकते हैं. ध्यान दें कि User ऑब्जेक्ट की सूची पाने के लिए, Gson का इस्तेमाल करते समय, कंस्ट्रक्टर को कॉल नहीं किया जाता या fromJson() फ़ंक्शन को फ़ैक्ट्री पास नहीं की जाती. ऐप्लिकेशन में तय की गई क्लास को, इनमें से किसी भी तरीके के बिना बनाना या इस्तेमाल करना, इस बात का संकेत है कि कोई लाइब्रेरी, ओपन-एंडेड रिफ़्लेक्शन का इस्तेमाल कर रही है:
- ऐप्लिकेशन क्लास, लाइब्रेरी या स्टैंडर्ड इंटरफ़ेस या क्लास को लागू करना
- कोड जनरेशन प्लगइन, जैसे कि KSP
class User(val name: String)
class UserList(val users: List<User>)
// This code runs in debug mode, but crashes when optimizations are enabled
Gson().fromJson("""[{"name":"myname"}]""", User::class.java).toString()
Gson पर R8 कैसे काम करता है, यह जानने के लिए, Gson के लिए उपभोक्ता के नियम देखें. जब R8
इस कोड का विश्लेषण करता है और उसे कहीं भी UserList या User इंस्टैंशिएट
नहीं दिखता, तो वह फ़ील्ड के नाम बदल सकता है या ऐसे कंस्ट्रक्टर हटा सकता है जिनका इस्तेमाल नहीं किया जा रहा है
. इससे आपका ऐप्लिकेशन क्रैश हो सकता है. अगर इसी तरह से किसी अन्य लाइब्रेरी का इस्तेमाल किया जा रहा है, तो आपको यह देखना चाहिए कि वे ऐप्लिकेशन को ऑप्टिमाइज़ करने में कोई समस्या तो नहीं पैदा कर रही हैं. अगर ऐसा है, तो उनका इस्तेमाल न करें.
Gson के नए वर्शन के साथ @SerializedName का इस्तेमाल करना
Gson के उपभोक्ता के नियमों के साथ काम करने वाले तरीके से अपने डेटा मॉडल तय करने के लिए, अपने फ़ील्ड को @SerializedName से एनोटेट करें. जैसे, यहां दिए गए स्निपेट में दिखाया गया है:
import com.google.gson.annotations.SerializedName
class User(@SerializedName("name") val name: String)
class UserList(@SerializedName("users") val users: List<User>)
@SerializedName एनोटेशन का इस्तेमाल करके, R8 को अपने मॉडल
क्लास को Gson के वर्शन 2.11.0 और उसके बाद के वर्शन में बंडल किए गए कीप नियमों से मैच करने की अनुमति मिलती है.
R8, एनोटेट किए गए फ़ील्ड और ज़रूरी कंस्ट्रक्टर को अपने-आप बनाए रखता है. इससे आपको अपने प्रोजेक्ट में, ProGuard के कॉन्फ़िगरेशन को मैन्युअल तरीके से बनाए रखने की ज़रूरत नहीं पड़ती. साथ ही, लाइब्रेरी के बंडल किए गए नियमों पर भरोसा किया जा सकता है.
ध्यान दें कि Room, Hilt, और कोड जनरेशन के साथ Moshi, ऐप्लिकेशन में तय किए गए टाइप बनाते हैं. हालांकि, रिफ़्लेक्शन की ज़रूरत से बचने के लिए, वे कोड जनरेशन का इस्तेमाल करते हैं.