
Application 클래스는 안드로이드 앱의 전역 상태를 관리하는 베이스 클래스다. 앱이 시작될 때 가장 먼저 생성되고, 앱이 완전히 종료될 때까지 메모리에 유지되는 싱글톤 객체라고 보면 된다.
생명주기: 모든 Activity, Service, BroadcastReceiver보다 먼저 생성되고 나중에 소멸된다. 앱 전체의 생명주기와 동일하다고 생각하면 쉽다.
전역 접근: 앱 어디서든 접근 가능한 전역 데이터나 설정을 저장하기에 적합하다.
실무에서 Application 클래스는 다음과 같은 용도로 활용된다
전역 리소스 관리: 앱 전체에서 공유하는 이미지 캐시, 사용자 로그인 상태, 앱 설정값(다크모드, 언어설정 등), 네트워크 상태 등을 관리한다. 이런 데이터들은 여러 화면에서 접근해야 하고 앱이 실행되는 동안 지속되어야 하기 때문에 Application에서 관리하는 것이 적절하다.
컴포넌트 초기화: Firebase, Crashlytics, 분석 도구 등 앱 전체에서 사용하는 라이브러리들을 앱 시작 시점에 초기화한다. 이런 라이브러리들은 한 번만 초기화하면 되고, 가능한 한 빨리 초기화되어야 하므로 Application.onCreate()에서 처리하는 것이 일반적이다.
의존성 주입 컨테이너: Retrofit 인스턴스, Database 인스턴스, Repository 객체 등 앱 전체에서 사용할 싱글톤 객체들을 생성하고 관리한다. Dagger, Hilt 같은 DI 프레임워크를 사용하지 않는 경우 Application에서 간단한 DI 컨테이너 역할을 수행할 수 있다.
앱 생명주기 모니터링: ActivityLifecycleCallbacks를 등록해서 앱이 포그라운드로 전환되거나 백그라운드로 이동할 때를 감지하고, 그에 따른 작업(사용자 세션 갱신, 알림 정리, 백그라운드 작업 시작/중지 등)을 수행한다.
메모리 관리 및 성능 최적화: 시스템의 메모리 부족 상황을 감지하고 캐시를 정리하거나 불필요한 리소스를 해제하는 등의 최적화 작업을 담당한다.
class MyApplication : Application() {
var isUserLoggedIn = false
var currentTheme = "light"
override fun onCreate() {
super.onCreate()
// 앱 시작 시 초기화 작업
initializeLibraries()
setupGlobalConfiguration()
}
// os Version 14 미만에서 사용
override fun onLowMemory() {
super.onLowMemory()
// 메모리 부족 시 처리
clearCaches()
}
override fun onTrimMemory(level: Int) {
super.onTrimMemory(level)
// 메모리 상태에 따른 분기
}
}
이 부분이 많은 개발자들이 헷갈려하는 지점이다. Application과 Activity는 생명주기와 리소스 관리 측면에서 명확한 차이가 있다.
지속성의 차이
리소스 관리 전략
Application에서는 장기 메모리 관리에 집중한다
override fun onTrimMemory(level: Int) {
super.onTrimMemory(level)
when (level) {
TRIM_MEMORY_UI_HIDDEN -> {
// UI가 숨겨졌을 때 - 캐시 일부 해제
imageCache.trimToSize(imageCache.size() / 2)
}
TRIM_MEMORY_COMPLETE -> {
// 앱이 종료될 가능성 높음 - 모든 캐시 해제
imageCache.evictAll()
}
}
}
Activity에서는 단기 메모리 관리에 집중한다
override fun onPause() {
super.onPause()
// 화면이 보이지 않을 때 메모리 절약
largeBitmap?.recycle()
}
override fun onDestroy() {
super.onDestroy()
// 액티비티 종료 시 모든 리소스 정리
mediaPlayer?.release()
}
Application 클래스를 잘못 사용하면 심각한 문제가 발생할 수 있다. 특히 메모리 누수는 주의해야 할 부분이다.
절대 하면 안 되는 것들:
class MyApplication : Application() {
// ❌ Activity Context 저장 - 메모리 누수!
private var activityContext: Context? = null
// ❌ View나 Activity 참조 - 메모리 누수!
private var currentActivity: Activity? = null
private var someView: View? = null
}
무거운 작업은 백그라운드에서:
override fun onCreate() {
super.onCreate()
// ❌ UI 스레드에서 무거운 작업 - 앱 시작 지연
// heavyInitialization()
// ✅ 백그라운드에서 초기화
GlobalScope.launch(Dispatchers.IO) {
heavyInitialization()
}
}
onTerminate()는 신뢰하지 말 것:
override fun onTerminate() {
super.onTerminate()
// ❌ 이 메서드는 실제 기기에서 호출되지 않음
// 중요한 정리 작업을 여기에 두면 안 됨
}
AndroidManifest.xml은 앱의 신분증 같은 역할을 한다. 안드로이드 시스템이 앱을 실행하기 전에 반드시 알아야 하는 모든 정보가 담겨 있다.
<application
android:name=".MyApplication"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".BackgroundService"
android:exported="false" />
</application>
Intent Filter는 안드로이드 앱들이 서로 소통할 수 있게 해주는 핵심 메커니즘이다. 다른 앱에서 보내는 암시적 Intent를 받을 수 있게 해준다.
이미지 공유 받기:
<activity android:name=".ImageShareActivity">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/*" />
</intent-filter>
</activity>
웹 링크 처리 (Deep Link):
<activity android:name=".ProductDetailActivity">
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https"
android:host="myshop.com"
android:pathPattern="/product/.*" />
</intent-filter>
</activity>
이렇게 설정하면 브라우저에서 https://myshop.com/product/123 링크를 클릭했을 때 우리 앱의 ProductDetailActivity가 실행된다.
Manifest에 Activity를 등록하지 않으면 어떻게 될까? 답은 간단하다. 런타임 에러가 발생한다.
// 등록되지 않은 Activity를 실행하려고 하면
val intent = Intent(this, UnregisteredActivity::class.java)
startActivity(intent) // ❌ ActivityNotFoundException 발생!
에러 메시지도 친절하게 알려준다
ActivityNotFoundException: Unable to find explicit activity class
{com.example.myapp/com.example.myapp.UnregisteredActivity};
have you declared this activity in your AndroidManifest.xml?
따라서 새로운 Activity를 만들 때마다 반드시 Manifest에 등록해야 한다
<activity
android:name=".NewActivity"
android:exported="false" />
Application 클래스와 AndroidManifest.xml은 안드로이드 앱의 기초가 되는 핵심 컴포넌트다. Application은 앱의 전역 상태와 장기간 지속되는 리소스를 관리하고, Manifest는 시스템에게 앱의 구조와 요구사항을 알려주는 역할을 한다.
이 둘을 제대로 이해하고 활용하면 더 안정적이고 효율적인 안드로이드 앱을 개발할 수 있다. 특히 메모리 누수 방지와 적절한 리소스 관리는 앱의 성능에 직접적인 영향을 미치므로 항상 주의깊게 다뤄야 한다.
개발하면서 "이게 Application에 들어가야 하나, Activity에 들어가야 하나?" 고민이 든다면, 그 데이터나 기능이 앱 전체에서 지속적으로 필요한지, 아니면 특정 화면에서만 필요한지를 생각해보자. 그러면 답이 나올 것이다.