
Activity, Service, BroadcastReceiver 간의 통신을 가능하게 해주는 메시징 객체, 액티비티 시작, 브로드캐스트 전송, 서비스 시작 등에 사용
호출하려는 컴포넌트를 직접 명시하여 실행, 특정 Activity, Service 시작
특정 컴포넌트를 지정하지 않고, 일반적인 작업을 정의, 시스템은 작업, 카테고리, 데이터 등을 기반으로 어떤 컴포넌트가 이 Intent를 처리할 수 있는지 판단
앱 컴포넌트가 어떤 종류의 Intent를 처리할 수 있는지를 정의하는 역할을 함.
AndroidManifest.xml에 선언되며, action, category, data 타입 등을 조합하여 특정 Intent 에 반응하도록 구성
현재 앱이 아닌 다른 앱이나 시스템 컴포넌트가 나중에 정의된 Intent를 대신 실행할 수 있도록 권한을 위임하는 객체. 앱이 생명주기를 벗어난 시점에도 작업이 수행되도록 할 수 있게 해준다.
PendingIntent.getActivity(), getService(), getBroadcast()
| 항목 | Intent | PendingIntent |
|---|---|---|
| 실행 주체 | 현재 앱이 직접 실행 | 다른 앱이나 시스템이 대신 실행 |
| 실행 시점 | 즉시 실행 | 나중에 실행될 수 있음 (예약, 알람 등) |
| 권한 | 현재 앱 권한으로만 실행 | 앱의 권한을 위임받아 실행 가능 |
| 용도 | 컴포넌트 직접 호출 | 시스템/타 앱에 Intent 실행을 위임 |
| 항목 | Serializable | Parcelable |
|---|---|---|
| 종류 | Java 표준 | Android 전용 |
| 성능 | 느림 | 빠름 |
| 가비지 생성 | 많음 | 적음 |
| 사용처 | 단순, 범용 | Android IPC, 성능 중요 시 |
다만, Parcel은 범용 직렬화 도구가 아니며, 영속적인 저장 용도로 사용해서는 안 됩니다.
왜냐하면 Parcel의 내부 구현은 향후 변경될 수 있으며, 이로 인해 이전 버전의 데이터를 읽을 수 없게 될 수 있기 때문입니다.
애플리케이션의 상태나 환경을 나타내며, 앱의 리소스 및 클래스에 접근할 수 있게 해주는 역할을 한다. Context는 안드로이드 시스템과 애플리케이션 컴포넌트 사이의 다리 역할을 하며, 리소스 접근, 데이터베이스 연결, 시스템 서비스 이용 등 다양한 작업을 가능하게 한다.
Activity를 시작하거나 레이아웃을 인플레이트하고, 시스템 리소스에 접근하는 대부분의 작업에 Context가 필요하다.
애플리케이션 전체 생명주기에 걸쳐 존재하며, 현재의 Activity나 Fragment에 종속되지 않는다.
사용 예시
특정 Activity의 생명주기에 연결된 Context이며, UI와 밀접한 작업에 사용된다.
사용 예시
getString(), getDrawable() 등을 통해 문자열, 이미지, 치수 등 리소스 획득startActivity(), startService() 등getSystemService()를 통해 ClipboardManager, ConnectivityManager 등 획득ContextWrapper는 Android에서 사용되는 기본 클래스이며, Context 객체를 감쌀 수 있도록 설계되어 있다. 이 클래스는 원래의 Context에 대한 호출을 위임하면서, 그 중간에서 동작을 수정하거나 확장할 수 있게 해준다. ContextWrapper를 사용하면, 원래의 Context를 변경하지 않고 기능을 커스터마이징할 수 있다.
Activity에서 this는 현재 Activity 인스턴스를 가리키며, 생명주기 및 UI 기능이 포함된 고수준의 Context를 제공한다. 반면 baseContext는 Activity가 기반하고 있는 저수준 Context이며, 커스텀 ContextWrapper와 같은 고급 기능 구현 시 유용하다. 일반적인 Android 개발에서는 this를 더 자주 사용하지만, baseContext에 대한 이해는 디버깅과 모듈화된 컴포넌트 구현에 도움이 된다.
전역 애플리케이션 상태와 생명주기를 유지하기 위한 기본 클래스 역할을 한다. 이는 애플리케이션의 진입점(entry point)으로 동작하며, Activity, Service, Broadcast Receiver 같은 다른 컴포넌트보다 먼저 초기화된다. Application 클래스는 애플리케이션 전체 생명주기 동안 사용할 수 있는 Context를 제공하므로, 공유 리소스를 초기화하는 데 적합하다.
AndroidManifest.xml 파일은 Android 프로젝트에서 필수적인 구성 파일로, 운영체제에 애플리케이션에 대한 중요한 정보를 전달한다. 이 파일은 애플리케이션과 운영체제 사이의 다리 역할을 하며, 컴포넌트, 권한, 하드웨어/소프트웨어 요구사항 등을 명시한다.
INTERNET, ACCESS_FINE_LOCATION, READ_CONTACTS 등과 같이, 앱이 접근하려는 자원에 대해 사용자에게 설명하고 허용받도록 한다.Activity 생명주기에 대한 흔한 후속 질문은 다음과 같다:
"Activity A를 실행한 뒤, Activity B를 실행하고, 다시 Activity A로 돌아올 때 발생하는 생명주기 전환을 설명할 수 있는가?"
이 질문은 Android 시스템이 여러 Activity 상태를 어떻게 관리하는지를 이해하고 있는지를 평가하기 위함이다.
onCreate() → onStart() → onResume()onPause() 호출 → UI를 일시 중지하고 시각적 리소스를 해제onCreate() → onStart() → onResume() → 포커스를 가져옴onStop() 호출 (Activity B가 완전히 A를 가릴 경우)onPause() 호출onRestart() → onStart() → onResume() 호출 → 다시 전면으로 복귀onStop() → onDestroy() 호출 → 메모리에서 제거onAttach()
Fragment가 자신의 부모 Activity에 연결되었을 때 호출되는 첫 번째 콜백이다. 이 시점에서 Fragment는 Activity Context에 접근할 수 있다.
onCreate()
Fragment가 초기화될 때 호출된다. 아직 UI는 생성되지 않았으며, 이 단계에서는 주요 구성요소를 초기화하거나 저장된 상태를 복원하는 작업이 이루어진다.
onCreateView()
Fragment의 UI가 처음으로 그려질 때 호출된다. 이 메서드에서는 Fragment의 레이아웃을 LayoutInflater를 사용해 인플레이트하고, 루트 뷰를 반환해야 한다.
onViewStateRestored()
Fragment의 뷰 계층 구조가 생성되고 나서, 저장된 상태가 뷰에 복원된 이후에 호출된다.
onViewCreated()
Fragment의 뷰가 생성된 직후 호출된다. 보통 이 메서드 안에서 UI 컴포넌트를 설정하거나 사용자 인터랙션을 처리하는 로직을 구현한다.
onStart()
Fragment가 사용자에게 보이게 되는 시점이다. Activity의 onStart()에 대응되며, 아직 전면 인터랙션은 불가능하다.
onResume()
Fragment가 전면에서 완전히 활성화되어 사용자와 상호작용이 가능한 상태가 된다. UI가 완전히 보이고, 사용자 입력을 받을 수 있다.
onPause()
Fragment가 전면이 아니게 되었지만 여전히 화면에 보이는 경우 호출된다. 포커스를 잃기 직전이며, 이 시점에는 계속해서 수행되면 안 되는 작업을 일시 중단해야 한다.
onStop()
Fragment가 사용자에게 더 이상 보이지 않게 되었을 때 호출된다. 이 메서드에서는 화면 밖에서 계속될 필요가 없는 작업을 중단해야 한다.
onSaveInstanceState()
Fragment가 파괴되기 전에 UI 상태 데이터를 저장할 때 호출된다. 나중에 복원할 수 있도록 상태를 저장한다.
onDestroyView()
Fragment의 뷰 계층이 제거될 때 호출된다. 이 시점에서는 어댑터 제거, 뷰 참조 제거 등과 같이 뷰 관련 리소스를 정리해야 한다.
onDestroy()
Fragment 자체가 파괴될 때 호출된다. 이 단계에서는 모든 리소스를 정리해야 하지만, Fragment는 여전히 부모 Activity에 연결된 상태일 수 있다.
onDetach()
Fragment가 부모 Activity로부터 분리될 때 호출된다. 이 단계가 끝나면 Fragment 생명주기는 종료된다.
fragmentManager와 childFragmentManager의 선택은 UI의 계층 구조에 따라 달라진다. Activity에서 전체 UI를 구성할 경우 fragmentManager를 사용하고, Fragment 내부에서 독립적인 구조가 필요할 경우 childFragmentManager를 사용한다. 각 범위와 생명주기를 명확히 이해함으로써 Android 애플리케이션의 구조를 더 잘 모듈화할 수 있다.
Service는 사용자 인터페이스와 독립적으로 장시간 실행되는 작업을 수행할 수 있게 해주는 안드로이드의 백그라운드 컴포넌트이다.
Started Service는 애플리케이션 컴포넌트가 startService()를 호출할 때 시작된다. 이 서비스는 명시적으로 stopSelf() 또는 stopService()를 호출할 때까지 백그라운드에서 계속 실행된다.
예시 사용처
Bound Service는 다른 컴포넌트가 bindService()를 통해 서비스에 바인딩할 때 활성화된다. 하나 이상의 클라이언트가 바인딩된 동안 서비스는 활성 상태이며, 모든 클라이언트가 연결을 해제하면 자동으로 종료된다.
예시 사용처
Foreground Service는 지속적인 알림을 표시하면서 실행되는 특수한 형태의 서비스이다. 음악 재생, 내비게이션, 위치 추적 등 사용자가 항상 인지하고 있어야 하는 작업에 적합하다.
사용자 인식 가능성(User Awareness)
일반 서비스는 백그라운드에서 사용자에게 보이지 않게 실행될 수 있지만, 포그라운드 서비스는 반드시 알림을 통해 사용자에게 표시되어야 한다.
우선순위(Priority)
포그라운드 서비스는 시스템 메모리가 부족할 때 일반 서비스보다 종료 우선순위가 낮다. 즉, 잘 종료되지 않음.
사용 사례
일반 서비스는 가벼운 백그라운드 작업에 적합하고, 포그라운드 서비스는 장기 실행되며 사용자에게 인식되어야 하는 작업에 적합하다.
BroadcastReceiver는 앱이 시스템 전역 브로드캐스트 메시지 또는 앱 내부 브로드캐스트를 수신하고 이에 응답할 수 있도록 해주는 컴포넌트다. 이 브로드캐스트는 시스템이나 다른 앱이 다양한 이벤트를 알릴 때 전송되며, 예를 들어 배터리 상태 변화, 네트워크 연결 상태 변경, 또는 앱 내부에서 정의한 커스텀 인텐트 등이 있다.
BroadcastReceiver는 시스템 또는 앱 수준의 동적 이벤트에 반응할 수 있는 반응형 애플리케이션을 구성하는 데 유용하다.
System Broadcasts (시스템 브로드캐스트)
Android 운영체제가 시스템 이벤트를 앱에 전달하기 위해 전송한다. 예: 배터리 부족, 시간대 변경, 네트워크 연결 상태 변화 등
Custom Broadcasts (커스텀 브로드캐스트)
앱이 특정 이벤트나 데이터를 앱 내부 또는 다른 앱과 통신하기 위해 직접 전송하는 브로드캐스트
ContentProvider는 구조화된 데이터를 관리하고, 앱 간에 데이터를 공유할 수 있도록 표준화된 인터페이스를 제공하는 컴포넌트이다. ContentProvider는 앱 또는 외부 앱이 데이터를 조회(query), 삽입(insert), 수정(update), 삭제(delete)할 수 있게 해주는 중앙 저장소 역할을 하며, 데이터의 일관성과 보안을 유지한다.
특히 여러 앱이 동일한 데이터에 접근할 필요가 있을 때, 또는 앱 내부의 DB나 파일 시스템 구조를 외부에 노출하지 않고 데이터를 제공하고자 할 때 유용하다.
ContentProvider의 주 목적은 데이터 접근 로직을 캡슐화하여, 앱 간 데이터 공유를 더 쉽고 안전하게 만드는 것이다. SQLite 데이터베이스, 파일 시스템, 네트워크 기반 데이터 등 다양한 소스를 추상화하고, 이들에 접근하기 위한 통일된 API를 제공한다.
ContentProvider는 데이터를 접근할 수 있는 URI (Uniform Resource Identifier)를 사용한다. URI는 다음과 같이 구성된다:
com.example.myapp.provider)/users, /products)/users/42)구성 변경을 올바르게 처리하는 것은 화면 회전, 언어 변경, 다크/라이트 모드 전환, 글꼴 크기 조정 등의 이벤트 중에도 끊김 없는 사용자 경험을 유지하는 데 매우 중요하다. 안드로이드 시스템은 이러한 변경이 발생하면 기본적으로 Activity를 종료 후 재생성하며, 이로 인해 일시적인 UI 상태가 손실될 수 있다.
안드로이드는 가비지 컬렉션(Garbage Collection) 메커니즘을 통해 메모리를 관리한다. 이는 사용되지 않는 메모리를 자동으로 회수하여, 앱과 서비스에 필요한 메모리가 효율적으로 할당되도록 한다.
안드로이드의 런타임 환경(Dalvik 또는 ART)은 메모리 사용을 모니터링하면서 참조되지 않는 객체를 정리하며, 메모리 과다 소비를 방지한다. 시스템 메모리가 부족할 경우, Low-Memory Killer가 백그라운드 프로세스를 종료시켜 포그라운드 앱의 안정적인 동작을 보장한다.
메모리 누수란 앱이 더 이상 필요하지 않은 객체에 대한 참조를 계속 유지하고 있어, 가비지 컬렉터가 메모리를 회수하지 못하는 상황을 말한다. 이는 메모리 부족, 성능 저하, 앱 강제 종료로 이어질 수 있다.
collectAsStateWithLifecycle() 등을 사용하여 컴포넌트 생명주기에 맞게 자동으로 자원을 해제하도록 한다.applicationContext를 사용한다.onPause() 또는 onStop() 등 적절한 시점에 unregister 또는 removeObserver()로 해제해야 한다.WeakReference를 사용해 GC의 회수를 허용한다.close()를 반드시 호출한다.onDestroyView() 또는 onDetach()에서 자원을 명시적으로 해제해야 한다.ANR은 "Application Not Responding"의 약자로, 안드로이드 앱의 메인 스레드(UI 스레드)가 너무 오랫동안 차단되었을 때 발생한다. 보통 5초 이상 응답이 없으면 시스템은 ANR 대화상자를 띄워 사용자에게 앱 종료 또는 대기 여부를 묻는다.
ANR은 사용자 경험을 심각하게 저하시킬 수 있으며, 아래와 같은 상황에서 발생할 수 있다:
ANR을 방지하려면 메인(UI) 스레드를 항상 응답 가능한 상태로 유지해야 하며, 연산이 오래 걸리는 작업은 백그라운드로 옮겨야 한다.
AsyncTask, Executors, Thread 등을 사용해 백그라운드에서 처리해야 한다.Dispatchers.IO에서 처리하도록 한다.WorkManager를 통해 예약 및 실행한다.Paging 라이브러리를 통해 부분적 로딩을 구현한다.ViewModel을 통해 상태를 유지한다.rememberSaveable도 좋은 선택지다.딥 링크는 외부 소스(예: URL, 알림, 이메일 등)로부터 앱의 특정 화면이나 기능으로 직접 이동할 수 있도록 해주는 메커니즘이다. 이를 통해 사용자 경험을 개선하고 앱 내 특정 콘텐츠로 빠르게 접근하게 할 수 있다.
딥 링크를 처리하려면 AndroidManifest.xml에 정의하고, 해당 Activity에서 인텐트를 처리해야 한다.
Task는 일반적으로 사용자가 앱 런처에서 Activity를 실행할 때 생성된다. 하나의 Task는 여러 앱에 걸쳐 존재할 수 있으며, Intent와 LaunchMode 설정에 따라 Task 간 Activity 이동이 가능하다.
예를 들어, 이메일 앱에서 링크를 클릭해 브라우저를 열면, 해당 브라우저 Activity는 같은 Task 안에 포함될 수도 있다. Task는 포함된 모든 Activity가 종료될 때까지 유지된다.
Back Stack은 Task 내 Activity들의 실행 이력을 유지한다. 사용자가 새 Activity로 이동하면 현재 Activity는 Stack에 푸시되고, 새 Activity가 최상단에 위치한다.
사용자가 뒤로가기 버튼을 누르면 가장 위의 Activity가 제거되고, 그 아래에 있던 Activity가 다시 보여진다. 이러한 방식은 사용자에게 직관적인 내비게이션 흐름과 연속성 있는 경험을 제공한다.
Android에서 Task와 Back Stack의 동작은 다음 두 가지 요소에 의해 결정된다:
Launch Mode는 Activity가 어떻게 인스턴스화되고 Back Stack에 추가되는지를 결정한다. Android에는 다음과 같은 네 가지 주요 Launch Mode가 있다:
singleTask와 유사하나, 해당 Activity는 독립적인 Task에 배치된다.Intent Flag는 런타임에서 Intent에 설정되어 Activity 실행 방식과 Back Stack 동작을 제어하는 플래그이다.
대표적인 플래그는 다음과 같다:
FLAG_ACTIVITY_NEW_TASKFLAG_ACTIVITY_CLEAR_TOPonNewIntent() 호출.FLAG_ACTIVITY_SINGLE_TOPsingleTop Launch Mode와 유사. 최상단에 있을 경우 재사용한다.FLAG_ACTIVITY_NO_HISTORYTask와 Back Stack은 안드로이드의 내비게이션 모델의 핵심이다.
Launch Mode와 Intent Flag를 적절히 설정하면, 복잡한 내비게이션 흐름에서도 일관성 있고 예측 가능한 사용자 경험을 제공할 수 있다.
Bundle은 Android에서 컴포넌트 간 데이터를 전달할 때 사용하는 키-값 쌍의 자료 구조이다. 이는 Activity, Fragment, Service 등 다양한 컴포넌트 간에 소량의 데이터를 효율적으로 전달할 수 있도록 설계되었다. Bundle은 가볍고 직렬화가 가능하여, Android 운영체제가 데이터를 저장하고 전달하는 데 적합하다.
Activity 간 데이터 전달에는 보통 Intent를 사용한다. 데이터를 putExtra()로 추가하고, 수신 Activity에서는 getIntent()로 값을 꺼낸다.
Fragment 간에는 보통 Bundle을 사용하여 데이터를 전달한다. 전달 Fragment에서 arguments에 Bundle을 설정하고, 수신 Fragment에서 getArguments()로 값을 읽는다.
Jetpack Navigation을 사용할 경우 Safe Args 플러그인을 적용하면 타입 안전한 데이터 전달이 가능하다.
같은 Activity 내 여러 Fragment가 데이터를 공유해야 한다면 Shared ViewModel이 적합하다. activityViewModels()를 통해 ViewModel 인스턴스를 공유할 수 있다.
ActivityManager는 Android의 시스템 서비스로, 디바이스에서 실행 중인 Activity, Task, 프로세스 등의 정보를 제공하고 이를 관리할 수 있도록 한다. Android 프레임워크의 일부로, 개발자가 앱의 생명주기, 메모리 사용량, 작업(Task) 상태 등을 제어할 수 있게 한다.
SparseArray는 android.util 패키지에 포함된 Android 전용 자료구조로, 정수형 키(int key) 를 객체 값(object value) 에 매핑할 수 있는 구조이다. 이는 HashMap<Integer, Object>와 비슷한 기능을 하지만, 메모리 효율성이 뛰어나고 Android에 최적화되어 있다.
Looper, Handler, HandlerThread는 스레드 관리와 비동기 작업 처리를 위해 함께 작동하는 Android의 핵심 컴포넌트들이다.
이들은 백그라운드 스레드에서 작업을 수행하면서, UI 업데이트 등은 메인 스레드와 안전하게 통신할 수 있도록 해준다.
| 구분 | Dalvik | ART |
|---|---|---|
| 컴파일 방식 | JIT (실행 중 컴파일) | AOT (설치 시 컴파일) |
| 실행 속도 | 느림 (매번 컴파일) | 빠름 (기계어 사전 생성) |
| CPU 사용량 | 높음 | 낮음 |
| 앱 시작 시간 | 지연 | 빠름 |
| 메모리 관리 | 기본 GC | 향상된 GC |
| 디버깅/분석 | 제한적 | 향상된 프로파일링 지원 |
.dex 파일로 변환하여 ART 또는 Dalvik에서 실행 가능하게 만듦APK는 전통적인 앱 배포 형식으로, 설치 가능한 완전한 패키지입니다.
AAB는 Google에서 도입한 퍼블리싱 전용 포맷입니다.
직접 설치할 수 있는 형식이 아닌, Google Play에서 처리 후 사용자 기기에 맞춘 APK로 변환되어 설치됩니다.
bundletool 등의 도구 사용 필요| 항목 | APK | AAB |
|---|---|---|
| 형식 목적 | 설치 가능 패키지 | 배포용 퍼블리싱 포맷 |
| 리소스 포함 | 모든 기기용 리소스를 포함 | 기기별 최적화된 리소스만 포함된 APK 생성 |
| 파일 크기 | 비교적 큼 | 사용자에게 전달되는 APK 크기 작음 |
| 배포 방식 | 직접 배포 및 sideloading 가능 | Google Play를 통해 최적화된 APK 생성 및 설치 |
| 설치 가능성 | 바로 설치 가능 | 직접 설치 불가, bundletool 필요 |
| 구성 관리 | 개발자가 수동 관리 | Google Play가 자동 구성 최적화 처리 |
| 호환성 | 모든 스토어 및 기기에서 사용 가능 | Google Play 중심, 타 스토어 미지원 가능성 있음 |
R8은 Android의 빌드 프로세스에 내장된 코드 축소 및 최적화 도구입니다.
이전의 ProGuard를 대체하며, APK 또는 AAB 파일의 크기를 줄이고 실행 성능을 향상시키기 위해 사용됩니다.
Service 가 실행 중인 프로세스→ Android는 낮은 우선순위의 프로세스를 먼저 종료하여 시스템의 안정성과 성능을 유지합니다
왜 Activity, Service, BroadcastReceiver, ContentProvider를 안드로이드의 4대 컴포넌트라고 부르나요?
Activity, Service, BroadcastReceiver, ContentProvider는 Android의 4대 구성요소(Four Major Components) 로 불립니다.
그 이유는 이 네 가지가 Android 애플리케이션이 시스템 및 다른 앱과 상호작용할 수 있게 해주는 핵심 구성 블록이기 때문입니다.
이들은 앱의 수명주기를 관리하고, 행동을 정의하며, 프로세스 간 통신(IPC) 을 가능하게 함으로써
Android의 앱 실행 및 관리 모델과 긴밀하게 연결되어 있는 핵심 요소입니다.