सामग्री पर जाएं
सभी पोस्ट

Android पर Baseline Profiles: 2026 में आपका कोल्ड-स्टार्ट टाइम असल में क्या तय करता है

Android Baseline Profiles के लिए एक व्यावहारिक गाइड — Macrobenchmark से इसे जनरेट करना, Gradle में जोड़ना, असली फायदे को मापना, और कोल्ड स्टार्ट को प्रभावित करने वाली तीन और चीज़ें।

MFKAPPS 5 मिनट पढ़ना

कोल्ड स्टार्ट वह परफॉर्मेंस नंबर है जिसे हर यूज़र महसूस करता है लेकिन लगभग कोई इसे मापता नहीं। आप आइकन पर टैप करते हैं, एक पल के लिए खाली स्क्रीन या खिंची हुई स्प्लैश स्क्रीन दिखती है, फिर ऐप सामने आता है। 500ms से कम पर किसी को फर्क नहीं पड़ता। एक सेकंड से ज़्यादा होने पर, यह “धीमा” लगता है भले ही उसके बाद की हर स्क्रीन तुरंत खुले — पहला इंप्रेशन टिका रहता है, और ऐप आइकन ही वह पहला इंप्रेशन है।

इस नंबर का ज़्यादातर हिस्सा आपके लेआउट या डेटाबेस क्वेरी से जुड़ा नहीं होता। यह JIT कंपाइलर का काम है, जो बिना किसी प्रोफाइल के — जिसके खिलाफ ऑप्टिमाइज़ कर सके — आपके ऐप के सबसे ज़्यादा इस्तेमाल होने वाले कोड पाथ्स पर कोल्ड, इंटरप्रेटेड तरीके से काम करता है। Baseline Profiles इसी वार्म-अप को छोड़ने के लिए बनाए गए हैं, और यह उन कुछ Android परफॉर्मेंस टूल्स में से एक है जो एक बार की मेहनत में एक दोपहर लेते हैं और उसके बाद हर इंस्टॉल पर फायदा देते रहते हैं।

Baseline Profile असल में क्या है

Baseline Profile एक टेक्स्ट फाइल है — baseline-prof.txt — जो उन क्लासेज़ और मेथड्स की सूची देती है जिन्हें आपका ऐप अपने सबसे आम फ्लो में छूता है: कोल्ड स्टार्ट, और कोई भी अन्य यात्रा जिसे आप प्रोफाइल करना चुनते हैं। आप इसे APK/AAB के अंदर शिप करते हैं, और Android Runtime (ART) इन मेथड्स को पहली बार इस्तेमाल पर इंटरप्रेट या JIT-कंपाइल करने के बजाय पहले से (ahead-of-time) कंपाइल करने के लिए इसका इस्तेमाल करता है।

असर सीमित लेकिन असली है: यह आपके कोड को तेज़ नहीं बनाता, यह सिर्फ स्टार्टअप के दौरान चलने वाले खास कोड पर इंटरप्रिटेशन टैक्स हटाता है। Play पर, Google बताता है कि यह उन ऐप्स में जिनके पास पहले प्रोफाइल नहीं थी, आमतौर पर कोल्ड स्टार्ट टाइम को 20-30% तक कम कर देता है — आपका फायदा पूरी तरह इस बात पर निर्भर करता है कि आपके स्टार्टअप पाथ का कितना हिस्सा असल में कवर हुआ है।

Macrobenchmark से एक प्रोफाइल जनरेट करना

प्रोफाइल किसी असली, इंस्ट्रुमेंटेड रन से आनी चाहिए — इसे हाथ से लिखना उपयोगी नहीं होगा। androidx.benchmark.macro लाइब्रेरी यह काम करती है:

// build.gradle.kts (baselineprofile मॉड्यूल)
plugins {
    id("androidx.baselineprofile")
}

dependencies {
    baselineProfile(project(":app"))
}
@RunWith(AndroidJUnit4::class)
class BaselineProfileGenerator {
    @get:Rule
    val rule = BaselineProfileRule()

    @Test
    fun generate() = rule.collect(
        packageName = "com.mfk.hydrame",
        includeInStartupProfile = true,
    ) {
        pressHome()
        startActivityAndWait()
        // सिर्फ स्प्लैश नहीं, प्री-कंपाइल करने लायक फ्लो चलाएं।
        device.findObject(By.text("Log a glass")).click()
        device.waitForIdle()
    }
}

:app:generateBaselineProfile Gradle टास्क को किसी असली डिवाइस या ठीक-ठाक तेज़ एमुलेटर पर चलाएं (प्रोफाइल जनरेशन के लिए लगभग-root इंस्ट्रुमेंटेशन बिल्ड चाहिए, जिसे प्लगइन खुद संभाल लेता है)। यह उस स्क्रिप्टेड रन के दौरान छुई गई हर क्लास को रिकॉर्ड करता है और baseline-prof.txt को app/src/main/ में लिख देता है, जहां से AGP का baseline profile प्लगइन इसे रिलीज़ बिल्ड्स के लिए अपने आप उठा लेता है।

जो हिस्सा ज़्यादातर लोग छोड़ देते हैं: सिर्फ स्प्लैश स्क्रीन से आगे स्क्रिप्ट करें। अगर असली बाधा Room से मिले डेटा के साथ आपकी पहली लिस्ट रेंडरिंग है, या किसी विजेट की पहली प्रोवाइडर कॉल है, तो उस इंटरैक्शन को collect ब्लॉक में शामिल करें। जो प्रोफाइल सिर्फ onCreate() को कवर करती है वह असली फायदे का ज़्यादातर हिस्सा छोड़ देती है।

फायदे को ईमानदारी से मापना

स्टॉपवॉच और अपने अंगूठे पर भरोसा न करें। एक अलग macrobenchmark टेस्ट में StartupTimingMetric का इस्तेमाल करें, इसे प्रोफाइल के बिना वाले बिल्ड और के साथ वाले बिल्ड के खिलाफ चलाएं, और इतनी इटरेशन्स पर मीडियन की तुलना करें कि नॉइज़ दोनों दिशाओं में औसत हो जाए:

@Test
fun startupCompilationModes() {
    benchmarkRule.measureRepeated(
        packageName = "com.mfk.hydrame",
        metrics = listOf(StartupTimingMetric()),
        iterations = 10,
        startupMode = StartupMode.COLD,
        compilationMode = CompilationMode.Partial(baselineProfileMode = BaselineProfileMode.Require),
    ) {
        pressHome()
        startActivityAndWait()
    }
}

बेसलाइन तुलना रन के लिए compilationMode को CompilationMode.None() में बदल दें। दस इटरेशन एक उचित न्यूनतम है — डिवाइस की थर्मल स्थिति और बैकग्राउंड प्रोसेस इतना नॉइज़ जोड़ देते हैं कि तीन रन आपको किसी भी दिशा में गुमराह कर सकते हैं।

Baseline Profiles जो ठीक नहीं करतीं

ये स्टार्टअप के काम को असल में कम करने का विकल्प नहीं हैं। अगर आपका Application.onCreate() तीन SDK शुरू करता है, डेटाबेस को उत्सुकता से खोलता है, और एक भारी पहली स्क्रीन को इनफ्लेट करता है, तो प्रोफाइल उस काम को इंटरप्रेट करने में तेज़ बनाती है — यह काम को कम नहीं करती। फायदे इनके साथ जुड़कर बढ़ते हैं, इनकी जगह नहीं लेते:

  • गैर-ज़रूरी शुरुआत को टालना। जो कुछ पहले फ्रेम के लिए ज़रूरी नहीं है — एनालिटिक्स SDK, गैर-ज़रूरी WorkManager शेड्यूलिंग, रिमोट कॉन्फ़िग फेच — उसे onCreate() में नहीं बल्कि UI दिखने के बाद बैकग्राउंड डिस्पैचर पर चलाएं।
  • रिलीज़ बिल्ड्स में R8 फुल मोड। बाइटकोड को छोटा और ऑप्टिमाइज़ करने का मतलब है कि ART को शुरुआत में गुज़रने के लिए कम कोड मिलता है, चाहे प्रोफाइल हो या न हो।
  • उत्सुक सिंगलटन की जगह लेज़ी सिंगलटन। एक by lazy डेटाबेस इंस्टेंस जो पहली DAO एक्सेस पर शुरू होता है, अगर पहली स्क्रीन को अभी उसकी ज़रूरत नहीं है तो स्टार्टअप पर आपको कुछ भी खर्च नहीं करता।

मुझे यह Hydrame का होम-स्क्रीन विजेट बनाते समय पता चला: विजेट का अपना कोल्ड स्टार्ट (एक अलग प्रोसेस कॉन्टेक्स्ट, जिसमें सहारा लेने के लिए कोई वार्म Application नहीं) ऐप से भी धीमा था, क्योंकि प्रोफाइल में विजेट का कोई भी कोड पाथ नहीं था। Macrobenchmark स्क्रिप्ट में — सिर्फ ऐप की मेन एक्टिविटी ही नहीं बल्कि — विजेट-विशिष्ट सिनेरियो जोड़ने से यह अंतर काफी हद तक कम हो गया।

यह दोपहर कब काम की है

अगर आपका ऐप पहले से तेज़ है, तो Baseline Profile एक अच्छा एक्स्ट्रा है। अगर कोल्ड स्टार्ट Play Console के vitals डैशबोर्ड में पीले रंग में बैठा इकलौता मेट्रिक है, तो यह आमतौर पर सबसे ज़्यादा फायदे वाली दोपहर होती है जो आप बिता सकते हैं: न कोई आर्किटेक्चर बदलाव, न कोई फीचर रिस्क, बस एक जनरेट की गई फाइल और एक Gradle प्लगइन। इसे अपने असली क्रिटिकल पाथ्स से हर रिलीज़ में एक बार जनरेट करें, Macrobenchmark टेस्ट को CI में रखें ताकि कोई रीडिज़ाइन चुपचाप उस चीज़ से आगे न निकल जाए जो प्रोफाइल कवर करती है, और कोल्ड-स्टार्ट नंबर को किसी भी दूसरे रिग्रेशन की तरह ट्रीट करें — कुछ ऐसा जिसे आप निगरानी में रखते हैं, न कि कुछ ऐसा जिसे एक बार ठीक करके भूल जाते हैं।

// संबंधित पठन

जर्नल से और भी

MFKAPPS 6 मिनट पढ़ना

2026 में Jetpack DataStore: बिना एक भी सेटिंग खोए SharedPreferences से माइग्रेट करना

Android पर SharedPreferences से Jetpack DataStore पर जाने की एक व्यावहारिक गाइड — असिंक्रोनस दिक्कतें, मौजूदा वैल्यू को बचाने वाला माइग्रेशन तरीका, और इसे कैसे टेस्ट करें।

#android #engineering #kotlin
MFKAPPS 6 मिनट पढ़ना

Mintly बनाना: जब Android प्रोसेस को मारना चाहता है तब भी फोकस टाइमर को सटीक रखना

चल रहे Pomodoro टाइमर की विश्वसनीयता की समस्या एक बार वाले रिमाइंडर से ज़्यादा कठिन होती है। जानिए कैसे Mintly एक फोरग्राउंड सर्विस और वॉल-क्लॉक एंड टाइम की मदद से Doze, प्रोसेस डेथ और स्क्रीन-ऑफ ड्रिफ्ट से बचता है।

#android #engineering #mobile
MFKAPPS 6 मिनट पढ़ना

2026 में Android पर ML Kit बारकोड स्कैनिंग: Stocky एक सेकंड से भी कम समय में पैंट्री आइटम कैसे जोड़ता है

ML Kit और CameraX के साथ ऑन-डिवाइस बारकोड स्कैनिंग की एक व्यावहारिक 2026 गाइड — फॉर्मेट ट्यूनिंग, ऑफ़लाइन प्रोडक्ट लुकअप, और एक पैंट्री ऐप के पीछे का आंशिक-उपयोग गणित।

#android #engineering #kotlin