๐Ÿงช Testing, Debugging, and Performance

Reducing Android App Startup Time

Startup is your app's first impression, repeated every time a user opens it. Slow cold starts frustrate users and show up in Android vitals. This guide shows how to measure startup precisely and the changes that usually make the biggest difference.

โœ๏ธ Yunok Tech ๐Ÿ“… Updated โฑ 3 min read ๐ŸŽฏ Advanced
On this page
  1. Cold, warm and hot starts
  2. Metrics: TTID and TTFD
  3. Measuring reliably
  4. The highest-impact fixes
  5. Typical wins
  6. Common mistakes
  7. Frequently asked questions
  8. Conclusion

Every SDK added "just one line" to Application.onCreate(). Two years later, cold start takes three seconds on mid-range phones. Startup regressions creep in silently, so you need measurement, a budget, and a few structural fixes.

Cold, warm and hot starts

TypeWhat happensCost
ColdProcess created, Application and Activity created, first frame drawnHighest: optimise this
WarmProcess exists, but the Activity is recreatedMedium
HotActivity brought to the foregroundLowest

Metrics: TTID and TTFD

  • Time to Initial Display (TTID): until the first frame is drawn. Logcat prints it as "Displayed โ€ฆ".
  • Time to Full Display (TTFD): until the content the user cares about is shown. Report it by calling reportFullyDrawn(), or with Compose's ReportDrawnWhen.
Report full display in ComposeKotlin
@Composable
fun HomeScreen(state: HomeUiState) {
    ReportDrawnWhen { state is HomeUiState.Content }    // tells the system when real content is visible
    // ...
}
Cold start timeline with common delays Cold start timeline: process start, Application onCreate where SDK initialisation often adds hundreds of milliseconds, Activity onCreate and the first composition, first frame marking time to initial display, then loading content marking time to full display. process Application.onCreate (SDKs!) Activity + compose 1st frame content TTID TTFD The red segment is usually the cheapest to shrink.
Profile a cold start once with a system trace and you'll usually find the biggest item immediately.

Measuring reliably

  • Macrobenchmark with StartupTimingMetric on a release-like build. See the performance guide for code.
  • System traces (Perfetto or the Android Studio Profiler) to see what runs during startup.
  • Android vitals for real-user startup data.

The highest-impact fixes

1. Slim down Application.onCreate()

Defer non-critical initialisationKotlin
@HiltAndroidApp
class App : Application() {
    @Inject lateinit var crashReporting: CrashReporting          // keep: needed early
    @Inject lateinit var analytics: dagger.Lazy<Analytics>        // defer: created on first use
    @Inject lateinit var appScope: CoroutineScope                  // injected application scope

    override fun onCreate() {
        super.onCreate()
        crashReporting.init()
        appScope.launch(Dispatchers.Default) {
            delay(1_000)                                          // after the first screen settles
            analytics.get().init()
            RemoteConfigWarmup.fetch()
        }
    }
}

Ask of every initialiser: does the first screen need it? If not, defer it, make it lazy, or initialise it on first use.

2. Watch hidden initialisers

Some libraries initialise themselves through ContentProviders that run before Application.onCreate(). The App Startup library lets you consolidate initialisers into one provider, control dependencies between them, and disable automatic initialisation for libraries you want to start lazily.

3. Ship a Baseline Profile

Baseline Profiles pre-compile the code on your startup path. They're often one of the biggest single wins, especially for Compose apps. See Baseline Profiles.

4. Make the first screen cheap

  • Render cached data or a lightweight skeleton immediately. Load the rest asynchronously.
  • Avoid synchronous disk reads, such as large SharedPreferences, before the first frame.
  • Keep the first composition small. Defer heavy, below-the-fold UI.

5. Use the SplashScreen API correctly

Keep splash only while truly necessaryKotlin
class MainActivity : ComponentActivity() {
    private val viewModel: StartupViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        val splash = installSplashScreen()
        super.onCreate(savedInstanceState)
        // Keep the splash only until the minimum state (e.g. auth check from local storage) is ready
        splash.setKeepOnScreenCondition { !viewModel.isReady.value }
        setContent { AppRoot() }
    }
}

Don't keep the splash visible for network calls or artificial delays. That only hides a slow start.

Typical wins

SDK diet

Deferring analytics, ads and remote config initialisation often removes a large share of Application.onCreate time.

Baseline Profile

A measurable startup improvement with little code change. Verify it with Macrobenchmark.

Lazy DI graph

Lazy<T> and providers stop the whole object graph being created at launch.

Common mistakes

  • Measuring debug builds, or only on flagship phones.
  • Moving work to a background thread that the first screen then waits for anyway.
  • Blocking on network or remote config before showing anything.
  • No regression guard. Add a startup benchmark to CI.

Frequently asked questions

What's a good cold start time?

Faster is better, and Android vitals flags excessive startup times. Set a budget for your app on a mid-range device and track it over releases.

Does Hilt slow startup?

Hilt itself is fast (code generated at compile time), but eagerly creating many singletons can. Use lazy injection for non-critical dependencies.

Should I use multidex or other old tricks?

Modern minSdk levels support multidex natively. Focus on initialisation work and Baseline Profiles.

Conclusion

Faster startup comes from measuring cold starts on release builds, deferring everything the first screen doesn't need, controlling library initialisers, shipping a Baseline Profile, and keeping the first screen light, then guarding it with a benchmark.

Next step: go deeper on the biggest single lever in Baseline Profiles and App Performance.

Official references

๐Ÿ“ฑ Apps built by Yunok Tech

Real Android apps on Google Play, free to download.

See all our apps โ†’

Ready to build real Android applications?

Performance work starts with understanding how Android apps are built and how they behave at runtime. Strengthen those fundamentals and the profiling tools start to make sense.

Move beyond theory and strengthen your Android development skills with Yunoktech's Android course. Learn core concepts, practical implementation, modern Android development techniques, and the reasoning behind building maintainable applications.

Explore the Android course and take your next step as an Android developer.

Share: LinkedIn X / Twitter WhatsApp