Application Class
Android Application Class
1. What is the Application class?
The Android Application class represents the entire application process.
Android creates its object when the app process starts, before creating normal components such as:
- Activity
- Service
- BroadcastReceiver
It is commonly used for application-level initialization that should happen once for the current process.
Application = Whole application process
Activity = One screen
Fragment = Part of a screen
Service = Background component2. Simple example
Suppose an application contains three screens:
flowchart TD
A["MyApplication"] --> B["LoginActivity"]
A --> C["HomeActivity"]
A --> D["SettingsActivity"]
Activities may be created and destroyed many times, but the Application object normally remains alive while the app process remains alive.
However, Android can kill the process when it needs memory. The application does not control its process lifetime.
3. Creating a custom Application class
Step 1: Create the class
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
// Application-level initialization
initializeLogging()
initializeAnalytics()
}
private fun initializeLogging() {
Log.d("MyApplication", "Logging initialized")
}
private fun initializeAnalytics() {
Log.d("MyApplication", "Analytics initialized")
}
}Step 2: Register it in AndroidManifest.xml
<application
android:name=".MyApplication"
android:allowBackup="true"
android:theme="@style/Theme.MyApp">
<activity
android:name=".MainActivity"
android:exported="true" />
</application>Without android:name, Android uses the default Application implementation.
4. Internal working
During a cold app start, Android performs work approximately in this order:
flowchart TD
A["User launches app"] --> B["Android creates Linux process"]
B --> C["Application object is created"]
C --> D["Application.onCreate() runs"]
D --> E["Main Activity is created"]
E --> F["Activity.onCreate() runs"]
F --> G["UI is displayed"]
Android’s startup documentation describes process creation, application-object creation, main-thread launch, Activity creation, layout, and first drawing as important stages of a cold start. Heavy work in `Application.onCreate()` therefore delays the first screen.
Important: `ContentProvider` initialization can happen before `Application.onCreate()`. The method is guaranteed to run before Activity, Service, and BroadcastReceiver objects, excluding content providers.
5. Application lifecycle methods
The Application class does not have a complete UI lifecycle like Activity.
1. onCreate()
Called when the application process starts.
override fun onCreate() {
super.onCreate()
// Keep initialization lightweight
}Common uses:
- Initialize logging
- Initialize dependency injection
- Configure analytics or crash reporting
- Create an application-level dependency container
- Register Activity lifecycle callbacks
onCreate() should finish quickly because its execution affects startup time.
2. onTrimMemory()
Called when Android asks the process to reduce unnecessary memory usage.
override fun onTrimMemory(level: Int) {
super.onTrimMemory(level)
if (level >= TRIM_MEMORY_UI_HIDDEN) {
imageCache.clear()
}
}Possible actions include:
- Clearing image caches
- Removing unused objects
- Releasing memory-heavy resources
- Reducing temporary in-memory data
Do not depend on one exact trim-level value because Android can add intermediate levels.
3. onConfigurationChanged()
Called when a configuration changes while the application process is running.
Examples include:
- Language change
- Screen size change
- Dark/light mode change
- Orientation-related configuration changes
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
Log.d("MyApplication", "Configuration changed")
}Unlike an Activity, the Application object is not recreated for normal configuration changes. (Android Developers)
4. onLowMemory()
Historically used when the system was running low on memory.
override fun onLowMemory() {
super.onLowMemory()
}For modern Android development, memory handling should primarily use `onTrimMemory()`. The framework documentation notes that `onLowMemory()` is deprecated at API level 35 and is not called starting with API level 34.
5. onTerminate()
override fun onTerminate() {
super.onTerminate()
}Do not use it for production cleanup.
`onTerminate()` is used only in emulated process environments. On a real Android device, Android normally kills the process directly without calling this method.
Therefore, never depend on it for:
- Saving user data
- Closing a database
- Stopping services
- Sending analytics
- Clearing sessions
6. Common use cases
Application-level dependency container
class AppContainer {
val apiService: ApiService by lazy {
Retrofit.Builder()
.baseUrl("https://example.com/")
.build()
.create(ApiService::class.java)
}
}
class MyApplication : Application() {
lateinit var container: AppContainer
private set
override fun onCreate() {
super.onCreate()
container = AppContainer()
}
}Access it from an Activity:
val container =
(application as MyApplication).containerIn larger applications, Hilt or another dependency-injection framework is generally cleaner than repeatedly casting the Application object.
Hilt Application class
@HiltAndroidApp
class MyApplication : Application()Manifest:
<application
android:name=".MyApplication">
</application>@HiltAndroidApp generates the application-level Hilt dependency container.
Register Activity lifecycle callbacks
The Application class can observe all Activity lifecycle events within its process.
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
registerActivityLifecycleCallbacks(
object : ActivityLifecycleCallbacks {
override fun onActivityCreated(
activity: Activity,
savedInstanceState: Bundle?
) {
Log.d("Lifecycle", "${activity.localClassName} created")
}
override fun onActivityStarted(activity: Activity) = Unit
override fun onActivityResumed(activity: Activity) = Unit
override fun onActivityPaused(activity: Activity) = Unit
override fun onActivityStopped(activity: Activity) = Unit
override fun onActivitySaveInstanceState(
activity: Activity,
outState: Bundle
) = Unit
override fun onActivityDestroyed(activity: Activity) = Unit
}
)
}
}This can help with:
- Screen analytics
- Debug logging
- Tracking the current Activity
- Session tracking
The framework provides Application.ActivityLifecycleCallbacks for this purpose. (Android Developers)
7. Application class is not permanent storage
A common mistake is storing important data in the Application object:
class MyApplication : Application() {
var loggedInUser: User? = null
}This data is lost when Android kills the process.
flowchart TD
A["Application object"] -->|"Process is killed"| B["Data is removed from memory"]Use suitable persistent storage instead:
- Room for structured data
- DataStore for settings and small values
- Files for file-based information
- SavedStateHandle for screen state
- Server/database for important business data
The Application class can keep temporary process-level state, but it must not be the only source of important data.
8. Application Context
Because Application extends Context, it can provide an application-level context.
val appContext = applicationContextGood uses:
Toast.makeText(
applicationContext,
"Download completed",
Toast.LENGTH_SHORT
).show()val preferences = applicationContext.getSharedPreferences(
"settings",
Context.MODE_PRIVATE
)Do not use Application Context for operations that require an Activity or window, such as:
- Showing a normal Dialog
- Inflating theme-sensitive screen UI
- Starting UI without the required intent flags
- Accessing Activity-specific lifecycle state
9. Application vs Activity
| Application | Activity |
|---|---|
| Represents the app process | Represents one screen |
| Normally one instance per process | Multiple instances can exist |
| Created when process starts | Created when screen is opened |
| Has no UI | Displays UI |
| Survives Activity recreation | Can be destroyed during rotation |
| Used for process-wide setup | Used for screen-specific setup |
Does not have onResume() or onPause() | Has a complete UI lifecycle |
10. Application class does not detect background/foreground directly
The Application class does not provide callbacks like:
onAppForeground()
onAppBackground()Use ProcessLifecycleOwner for process-level foreground/background
class MyApplication : Application(), DefaultLifecycleObserver {
override fun onCreate() {
super.onCreate()
ProcessLifecycleOwner.get()
.lifecycle
.addObserver(this)
}
override fun onStart(owner: LifecycleOwner) {
Log.d("AppState", "App entered foreground")
}
override fun onStop(owner: LifecycleOwner) {
Log.d("AppState", "App entered background")
}
}ProcessLifecycleOwner combines Activity lifecycle information to represent the application process. It sends process-level start/resume and pause/stop events, while process destruction is not reported through ON_DESTROY.
11. Common mistakes
1. Performing heavy work in `onCreate()`
Bad:
override fun onCreate() {
super.onCreate()
downloadLargeFile()
readCompleteDatabase()
Thread.sleep(3000)
}This delays app startup and can contribute to an Application Not Responding error.
Better:
override fun onCreate() {
super.onCreate()
initializeOnlyRequiredComponents()
}Use lazy initialization for non-critical components.
Jetpack App Startup can also organize startup initializers, define dependency order, and support lazy initialization. (Android Developers)
2. Keeping Activity reference
Bad:
class MyApplication : Application() {
var currentActivity: Activity? = null
}A strong Activity reference can cause a memory leak.
Where tracking is necessary, use lifecycle callbacks carefully and keep a WeakReference, or redesign so an Activity reference is not required.
3. Assuming the Application object always exists
The Application object exists only while its process exists.
flowchart TD
A["App process is running"] --> B["Application object is available"]
B --> C["Android kills the process"]
C --> D["Application object and in-memory state are lost"]
4. Assuming one Application instance across multiple processes
An Android package can use multiple processes through android:process. Each process creates its own runtime state and, consequently, its own Application instance.
Therefore, an Application variable is not automatically shared between processes. The framework exposes `Application.getProcessName()` to identify the current process.
12. Interview-ready answer
The Android Application class represents the application process and is created when that process starts. A custom Application class is used for lightweight, process-wide initialization such as dependency injection, logging, analytics, or lifecycle callback registration. Its onCreate() runs before Activities, Services, and BroadcastReceivers, except that ContentProviders may initialize earlier. We should not store critical data in it because Android can kill the process at any time. We should also avoid heavy initialization because it directly increases app startup time.
Important interview questions
1. Is the Application class a singleton?
It behaves like one instance inside a particular process, but multiple processes have separate Application instances.
2. Does Application survive process death?
No. A new Application object is created when the process restarts.
3. Is Application.onCreate() called every time an Activity opens?
No. It is called when the application process is created.
4. Is onTerminate() called when the user removes the app from recent tasks?
No. It is not called on production Android devices.
5. Can Application Context show a Dialog?
Normally no, because a Dialog needs a window-owning Activity context.
6. Should API calls be made in Application onCreate()?
Only when absolutely necessary. Normal API calls should usually be made from the appropriate repository or use case and started by lifecycle-aware components.
7. Can Application store login data?
It can temporarily cache data, but persistent login information must be stored in DataStore, encrypted storage, a database, or another durable source.