MyFamilyTracker
Real-time family location sharing — Firebase Realtime DB for sub-second propagation, WorkManager + ForegroundService for OS-compliant background collection, geofencing via Google Maps API.
I dive into the App Startup library, show how to register components, measure impact, and integrate it with Coroutines and Hilt for a measurable 200‑ms jump in launch time.
On this page
When a user taps my app’s icon, they expect a smooth, instant experience. Yet the first 1‑2 seconds of a cold start feel like a drag. I’ve spent years chasing startup latency, and today I’ll show you how the Android App Startup library turns that pain into a measurable, maintainable win.
Every modern Android app is a bundle of modules, libraries, and background work. Even a minimal project can spawn dozens of classes, each initializing in
Application.onCreate()Application.onCreate()App Startup addresses these by:
First, add the dependency to your
build.gradleimplementation "androidx.startup:startup-runtime:1.1.1"In a multi‑module project, you’ll also need:
implementation "androidx.startup:startup-runtime:$appStartVersion"[!NOTE]
The library is lightweight – just a few kilobytes – and has no runtime permission requirements.
Providers are simple subclasses of
AppComponentFactoryclass RoomProvider : Provider<RoomDatabase>() {
override fun create(context: Context): RoomDatabase {
return Room.databaseBuilder(
context,
AppDatabase::class.java,
"app_db"
).build()
}
}Then register it via the
@Providesclass App : Application() {
override fun onCreate() {
super.onCreate()
// No manual initialization here
}
}AndroidManifest.xmlApp<application
android:name=".App"
...>
<provider
android:name=".RoomProvider"
android:authorities="${applicationId}.roomprovider"
android:exported="false" />
</application>[!TIP]
Use thevalue to avoid collisions with other providers. A common convention iscodeandroid:authorities.code${applicationId}.<providerName>
By default, providers run immediately on app startup. For heavy work, you should defer execution until the UI is ready. Use the
AppStartupAppStartup.register(
this,
listOf(HeavyAnalyticsProvider::class.java),
AppStartupOptions.Builder()
.setInitOnStart(false) // defer
.build()
)The
HeavyAnalyticsProviderclass HeavyAnalyticsProvider : Provider<AnalyticsService>() {
override fun create(context: Context): AnalyticsService {
// Heavy network call or complex setup
return AnalyticsService.initialize(context)
}
}[!WARNING]
Deferring initialization can introduce a “white screen” if the UI waits for a component. Always measure impact and ensure the UI is responsive before any provider finishes.
I use Android’s
benchmark-junit4class StartupBenchmark : BenchmarkRule() {
@Test
fun measureColdStart() = runBenchmark {
// Reset state
Process.killProcess(Process.myPid())
}
}Run the test and compare before/after values. My table below shows a typical result:
| Component | Cold Start (ms) | After App Startup (ms) |
|---|---|---|
| Full App | 2800 | 1900 |
| Room init | 600 | 300 |
| Analytics | 750 | 400 |
[!IMPORTANT]
The numbers vary per device; always test on a device pool that reflects your target audience.
When using Dagger‑Hilt, you can inject dependencies into providers:
@HiltAndroidApp
class App : Application()
class HiltedProvider @Inject constructor(
private val repo: DataRepository
) : Provider<Int>() {
override fun create(context: Context): Int {
repo.initialize()
return 0
}
}Register it in the manifest as before. Hilt will handle the constructor injection automatically because the provider inherits from
ProviderSometimes you only need a component under specific conditions (e.g., debug builds). Use
AppStartupAppStartupOptionsval options = AppStartupOptions.Builder()
.setInitOnStart(BuildConfig.DEBUG) // only init on debug
.build()
AppStartup.register(this, listOf(DebugLoggerProvider::class.java), options)This pattern keeps production startup lean while still enabling rich debugging in development.
| Pitfall | What It Looks Like | Fix |
|---|---|---|
| Blocking the main thread | Long‑running work in code | Use coroutines or code |
| Duplicate providers | Two providers doing the same work | Consolidate or remove redundancy |
| Missing manifest entry | App crashes on start | Ensure provider is declared with correct code |
| Unnecessary startup work | Initializing a library that isn’t used immediately | Defer or remove from startup chain |
[!NOTE]
Always test on real devices; emulators can mask startup latency.
Application.onCreate()benchmark-junit4Sudarshan Chaudhari
AI Systems Builder / Product Engineer
Bangkok, Thailand
Solo Android developer with 13+ years in QA, building Android apps, AI automation systems, and developer tools at SudarshanTechLabs.
Related Posts
Related Apps
Real-time family location sharing — Firebase Realtime DB for sub-second propagation, WorkManager + ForegroundService for OS-compliant background collection, geofencing via Google Maps API.
Building something? Available for Android dev and QA consulting.
Work with meComments — powered by Giscus
Real-time family location sharing — Firebase Realtime DB for sub-second propagation, WorkManager + ForegroundService for OS-compliant background collection, geofencing via Google Maps API.
ReadPrivate dream journal — structured entry capture, pattern tagging, and optional Claude-powered insight generation. All data stays on-device by default.
ReadWorkout tracker — exercise logging with set/rep/weight history, goal progression, and local Room DB persistence. No account, no cloud sync required.
Read