App Startup Optimization

📖 Concept

App startup time is one of the most critical performance metrics. Google recommends cold start < 500ms. At the senior level, you need to understand the startup phases, profiling tools, and optimization techniques.

Startup types:

  • Cold start: Process not running. Full initialization: Zygote fork → Application.onCreate() → Activity.onCreate() → first frame. Slowest.
  • Warm start: Process exists but Activity is recreated. Skips process creation.
  • Hot start: Activity is in memory, just brought to foreground. Fastest.

Cold start phases:

1. Process creation (Zygote fork)           ~50-100ms (OS, can't optimize)
2. Application.onCreate()                   ← YOUR optimization target
3. Activity.onCreate()                      ← YOUR optimization target
4. Layout inflation & measure/layout        ← YOUR optimization target
5. First frame rendered (TTID)              ← The metric that matters

Key metrics:

  • TTID (Time To Initial Display): Time until the first frame is drawn. Reported in Logcat as "Displayed" time.
  • TTFD (Time To Full Display): Time until all async data is loaded and the full UI is visible.

Optimization strategies:

  1. Lazy initialization: Don't initialize everything in Application.onCreate(). Use the App Startup library for on-demand initialization.
  2. Background initialization: Move non-critical init to background threads.
  3. Baseline Profiles: AOT-compile critical code paths for 30-40% faster startup.
  4. Reduce layout complexity: Fewer nested layouts = faster inflate and measure.
  5. Splash screen: Use the SplashScreen API (Android 12+) to provide instant visual feedback.

💻 Code Example

codeTap to expand ⛶
1// BAD: Heavy initialization in Application ❌
2class MyApplication : Application() {
3 override fun onCreate() {
4 super.onCreate()
5 // Each of these blocks the main thread!
6 Analytics.init(this) // 200ms
7 CrashReporting.init(this) // 100ms
8 ImageLoader.init(this) // 150ms
9 Database.init(this) // 300ms
10 // Total: 750ms blocked on main thread!
11 }
12}
13
14// GOOD: Lazy + background initialization ✅
15class MyApplication : Application() {
16 override fun onCreate() {
17 super.onCreate()
18 // Only critical, fast initializations on main thread
19 CrashReporting.init(this) // Must be first for crash capture
20
21 // Everything else: lazy or background
22 ProcessLifecycleOwner.get().lifecycle.addObserver(
23 object : DefaultLifecycleObserver {
24 override fun onCreate(owner: LifecycleOwner) {
25 CoroutineScope(Dispatchers.Default).launch {
26 Analytics.init(this@MyApplication)
27 ImageLoader.init(this@MyApplication)
28 }
29 }
30 }
31 )
32 }
33}
34
35// App Startup Library — declarative lazy initialization
36class AnalyticsInitializer : Initializer<Analytics> {
37 override fun create(context: Context): Analytics {
38 return Analytics.Builder(context).build()
39 }
40 override fun dependencies(): List<Class<out Initializer<*>>> {
41 return listOf(CrashReportingInitializer::class.java)
42 }
43}
44
45// Baseline Profiles — critical for startup optimization
46// baseline-prof.txt in app/src/main/
47// Tells ART to AOT-compile these methods
48// HSPLcom/myapp/MainActivity;->onCreate(Landroid/os/Bundle;)V
49// Generated via Macrobenchmark:
50@RunWith(AndroidJUnit4::class)
51class BaselineProfileGenerator {
52 @get:Rule
53 val rule = BaselineProfileRule()
54
55 @Test
56 fun generateBaselineProfile() {
57 rule.collect(packageName = "com.myapp") {
58 startActivityAndWait()
59 // Navigate through critical user journeys
60 device.findObject(By.text("Login")).click()
61 device.waitForIdle()
62 }
63 }
64}

🏋️ Practice Exercise

Practice:

  1. Profile your app's cold start time using adb shell am start -S -W
  2. Implement lazy initialization using the App Startup library
  3. Generate a Baseline Profile and measure the startup improvement
  4. Identify 3 things in your Application.onCreate() that can be deferred
  5. Explain the SplashScreen API vs a custom splash Activity
  6. What is the Zygote process and how does it speed up app creation?

⚠️ Common Mistakes

  • Initializing all SDKs synchronously in Application.onCreate() — this is the #1 cause of slow cold starts

  • Using a custom splash Activity instead of the SplashScreen API — adds an extra Activity creation to the startup path

  • Not measuring startup time properly — use Macrobenchmark, not manual timing

  • Ignoring Baseline Profiles — they can improve startup by 30-40% with minimal effort

💼 Interview Questions

🎤 Mock Interview

Mock interview is powered by AI for App Startup Optimization. Login to unlock this feature.