The first frame is quick; the first usable tap arrives eight seconds later. Reporting only the first frame would make this launch look much faster than it feels. Startup work needs a defined endpoint: the moment a person can complete the first useful action.
Name the milestones your launch actually passes
Android distinguishes time to initial display, TTID, from time to full display, TTFD. The first concerns the initial frame; the second concerns the app's fuller readiness. Add product-specific markers where a game also needs a menu, authenticated profile or playable scene.
Keep platform metrics and custom markers separate. A first-frame metric can improve while the playable scene becomes slower. Record exactly what each marker means, including whether remote content or sign-in is required.
Milestone | Example meaning | Potential hidden work |
First frame | The app draws its initial surface | Engine and profile loading may continue |
Usable menu | Navigation and essential controls respond | An optional catalogue can still load |
Profile ready | The intended account state is available | Some online modes may need another service |
First playable scene | The user can issue a meaningful game input | Later levels may remain downloadable |
Separate cold launch from returning to a running app
A cold start creates the app process from scratch. A warm start performs a subset of launch work, while a hot start can reuse more of the existing activity and process state. Exact measurement and classification follow the platform tooling.
Do not compare a newly installed build's cold launch with a previous build's already-running state. Record whether the process existed, whether data had been cached and whether the route followed installation, an update or ordinary navigation.
First launch can also include database creation, unpacking and setup that later launches skip. Report it separately. If first-run processing is necessary, persist completion safely so a restart does not repeat expensive work or skip a half-finished step.
Trace the critical path through initialization
A task is on the critical path when startup readiness must wait for it. Trace actual dependencies instead of assuming every initialization call is equally urgent. An analytics SDK, news panel or optional social feature should have a clear reason before it delays basic navigation.
Suppose an example launch performs 300 ms of local setup, waits 700 ms for profile data and then spends 400 ms preparing a scene. In sequence, that path takes 1,400 ms. If the last two tasks are truly independent and can overlap after local setup, the theoretical path becomes 1,000 ms: 300 plus the longer 700 ms task.
That calculation excludes contention, scheduling and additional dependencies. Parallel work can increase memory peaks or compete for CPU and storage. Confirm the improvement in a trace rather than assuming that more background tasks always shorten launch.
Keep long work away from the interactive thread
Large file reads, database queries and synchronous network waits can prevent the interface from processing input. A loading animation does not make blocking work asynchronous. Inspect thread activity and wait relationships around the visible freeze.
A background task can still block the main thread if initialization immediately waits for its result. Locks can also create a cycle in which each task waits for the other. Capture a hang while it is occurring; a screenshot of the splash screen cannot show the blocked ownership chain.
Split work into necessary readiness steps and deferrable work. Keep the UI state explicit: initializing, waiting for connection, restoring data, ready or failed. Each waiting state should have a known owner and a way to stop waiting when its operation has ended unsuccessfully.
Prevent offline launch from becoming an endless spinner
A device can have a network interface without a usable route to the app's backend. Captive portals, DNS failures and a failing service produce different symptoms. Use bounded timeouts and display the outcome appropriate to the feature.
If an offline mode is supported, load the permitted local state without waiting indefinitely for optional services. If online verification is essential, explain what is unavailable and offer an explicit retry. Never turn a temporary connection failure into a new empty account.
Retain the identity of a timed-out operation. A late response from a previous launch attempt must not overwrite the current screen or apply data to a different account. Repeated taps on Retry should not start an unbounded stack of initialization flows.
Give every initialization dependency a completion path
A consent screen, login prompt and remote-configuration fetch can accidentally wait on one another. For example, initialization waits for a login result while the login UI waits for initialization to finish. This is a dependency cycle, not a slow network.
Draw the prerequisite graph for the first usable screen. Ensure that cancellation, denied permission and unsupported optional features also produce defined outcomes. Check the path where a callback never arrives, as well as the path where it arrives twice. Resolve each initialization attempt once and make repeated events harmless to the current state.
Treat migration and restore as resumable operations
After an update, a local database or save format may need conversion. Test with the largest realistic existing dataset, including interrupted and partly migrated records. A clean installation cannot exercise that path.
Record migration progress at safe boundaries and preserve the invariants needed for restart. If conversion fails, the app should keep recoverable data and report the relevant error. Automatically deleting the database may make launch succeed while destroying the user's history.
Separate necessary data from replaceable cache
A damaged image cache can often be rebuilt, but a guest player's only save cannot. Name the storage category before implementing a “reset startup data” action. Provide narrow repair paths for replaceable content rather than clearing the entire application directory.
Check low-storage behaviour during migration. Reading the old database successfully does not mean there is enough room to write the new representation, transaction journal or temporary files. Preserve a recoverable starting point until the new state is committed.
Measure repeated launches with a fixed definition
Select representative devices and a release-like build.
Record startup state, storage state and the starting account.
Use the same launch route and milestone definitions.
Capture first-run and routine launches separately.
Repeat enough times to reveal variation and retain traces for slow runs.
If a test's median usable-menu time is 1.2 seconds but p95 is 4.8 seconds, focus on what differs in the slower launches. The figures describe a hypothetical measurement set, not platform thresholds. A median alone cannot show whether a large minority waits much longer.
Percentiles from very small samples are unstable. A p99 from ten launches cannot support a precise claim about one-in-a-hundred behaviour. Report the sample count, percentile calculation and device group alongside the values.
Verify deep links and interrupted launch paths
Opening the app icon is only one entry route. A notification, account callback or supported link may request a destination before normal initialization has completed. Store a validated pending route and resolve it after the required state exists.
Test backgrounding during setup, returning after process loss and opening two links in quick succession. Ensure the loading screen does not survive after its task has finished, and that an old error does not replace a successful later attempt.
A startup repair is complete when the first useful action arrives predictably, optional failures remain contained and existing data survives interrupted launches. Keep the timing definition with the benchmark so a future change cannot improve a number merely by moving the endpoint.
Use the same endpoint for every launch measurement: for example, the first moment a player can open the main menu and start a level. Tag traces by cold, warm and returning launch. If a migration adds a one-time delay, report that separately from routine launches. A single fast second attempt should not erase a slow first launch for users upgrading from an older build.