Interview QuestionPractical QuestionFollow-up Questions

App Startup and Cold Start Optimization

skydovesJaewoong Eum (skydoves)||11 min read

App Startup and Cold Start Optimization

When a user taps your app icon and nothing is in memory, the system creates a new process, loads the Application class, instantiates ContentProviders, calls Application.onCreate(), then launches the target Activity and draws the first frame. This sequence, called a cold start, is the slowest path to a visible UI. Every millisecond in this window is felt directly by the user as a blank screen or frozen splash.

ContentProviders are a significant contributor because every library that registers its own ContentProvider (Firebase, WorkManager, Lifecycle) adds initialization work before your application code even runs. The App Startup library addresses this by consolidating multiple ContentProviders into a single one with a dependency aware initialization system. By the end of this lesson, you will be able to:

  • Describe the cold start sequence from process creation to the first drawn frame.
  • Explain why ContentProviders are a startup bottleneck and how App Startup consolidates them.
  • Trace how AppInitializer resolves the dependency graph between initializers.
  • Identify practical strategies for reducing cold start time: lazy initialization, baseline profiles, and tracing.
  • Apply initializeComponent() to defer non essential initialization until it is needed.

The cold start sequence

A cold start happens when the app's process does not exist. The system performs several steps before your code runs:

  1. The system forks a new process from Zygote.
  2. The runtime creates the Application object.
  3. All ContentProviders declared in the merged manifest are instantiated and their onCreate() methods are called.
  4. Application.onCreate() is called.
  5. The target Activity is created and the first frame is measured, laid out, and drawn.

Step 3 is where many apps lose time. Each ContentProvider runs on the main thread before Application.onCreate(). If five libraries each register their own ContentProvider to auto initialize, that is five instances created, five onCreate() calls, all blocking the main thread before your app code starts. The system cannot parallelize this because ContentProviders are instantiated sequentially in the order they appear in the merged manifest.

A warm start skips step 1 (the process already exists but the Activity was destroyed). A hot start skips everything except bringing the existing Activity to the foreground. Cold starts are the most expensive and the most important to optimize because they determine the user's first impression.

Why ContentProviders are expensive

ContentProviders were designed for cross process data access. Libraries adopted them as an initialization hook because ContentProvider.onCreate() is called automatically before Application.onCreate(), giving libraries a way to self initialize without requiring the developer to add code to the Application class.

The cost comes from two sources. First, each ContentProvider adds class loading overhead: the runtime must find, load, and verify the class. Second, the onCreate() method often performs actual initialization work such as reading SharedPreferences, setting up singleton instances, or registering lifecycle observers.

When you merge dependencies from Firebase (multiple providers), WorkManager (WorkManagerInitializer), Lifecycle (ProcessLifecycleOwnerInitializer), and other libraries, the combined cost can easily add 50-150ms to cold start time on mid range devices. This time is invisible to most developers because it happens before any of their code runs.

App Startup: One ContentProvider to replace many

The App Startup library replaces multiple ContentProviders with a single InitializationProvider. Libraries declare their initializers as metadata entries in the manifest, and InitializationProvider discovers and runs them all in one pass.

The InitializationProvider itself is a minimal ContentProvider. Its onCreate() method delegates everything to AppInitializer:

public class InitializationProvider extends ContentProvider {
    @Override
    public final boolean onCreate() {
        Context context = getContext();
        if (context != null) {
            Context applicationContext = context.getApplicationContext();
            if (applicationContext != null) {
                AppInitializer.getInstance(context)
                    .discoverAndInitialize(getClass());
            }
        }
        return true;
    }
}

This interview continues for subscribers

Subscribe to Dove Letter for full access to exclusive interviews about Android and Kotlin development.

Become a Sponsor