이 포스팅은 안드로이드 공식 문서를 기반으로 정리한 내용입니다.
아키텍처 가이드에 대한 내용을 정리한 것 입니다.
많은 분들에게 도움이 되었으면 좋겠습니다.
참고는 맨 아래에 있습니다.
1. 들어가며: 왜 아키텍처가 필요한가?
- 수명 주기 제약: OS가 메모리 확보를 위해 언제든지 액티비티/프래그먼트를 중단·재시작
- 제한된 리소스: 네트워크 단절, 메모리 부족 상황에서도 안정적 동작 필요
- 여러 컴포넌트: Activity, Fragment, Service, ContentProvider, BroadcastReceiver 등
- 결론: UI 컴포넌트에 상태를 직접 담지 않고, 견고·확장·테스트 가능한 구조가 필수

2. 일반 아키텍처 원칙
2.1 관심사 분리 (Separation of Concerns)
요약 공식 권장사항
| - Activity/Fragment: UI와 OS 이벤트만 담당 | 적극 권장됨: “계층화된 아키텍처” → 관심사 분리 필수 |
| - 로직·상태: ViewModel·Repository 등 별도 클래스에서 처리 | - UI 레이어는 Composable·Activity·Fragment만으로 구성- 데이터 레이어는 Repository로만 접근 |
이유
- UI 컴포넌트는 언제든 소멸할 수 있어 상태 보관 부적절
- 분리된 로직은 단위 테스트와 리팩토링이 용이
2.2 데이터 모델 → UI 도출
요약 공식 권장사항
| - Model 변경 시 View 자동 업데이트 | 적극 권장됨: “단방향 데이터 흐름(UDF)” 패턴 따르기 |
| - 데이터 모델은 지속 가능해야 함 (DB/파일 등에 보관) | - UI Layer ← StateFlow / LiveData ← ViewModel- UI → ViewModel → Repository |
이유
- OS가 프로세스를 재시작해도 DB/SharedPreferences에 보존
- 네트워크 불안정 시 로컬 캐시로 계속 서비스 제공
2.3 단일 소스 오브 트루스 (SSOT)
요약 공식 권장사항
| - 하나의 데이터 타입은 하나의 Repository가 수정 권한을 가짐 | 적극 권장됨: “계층화된 아키텍처” 데이터 레이어에 SSOT 할당 |
이점
- 변경 지점 한곳 집중 → 버그 추적 용이
- 데이터 무결성 보장
2.4 단방향 데이터 흐름 (UDF)
┌──────────┐ 사용자 이벤트 ┌──────────┐
│ UI Layer│ ────────────────────────> │ ViewModel│
└──────────┘ 상태 요청 │ /Domain │
▲ │
│ 데이터 스트림 (Flow/LiveData) │
└──────────────────────────────────────┘
- 데이터: Repository → UseCase(Domain, Optional) → ViewModel → UI
- 이벤트: UI → ViewModel → Repository
공식 권장사항: “단방향 데이터 흐름(UDF)을 따릅니다.” (적극 권장됨)
3. 권장 앱 레이어 구성
3.1 UI 레이어
- 역할: 화면 렌더링 · 사용자 입력 수집
- 구성 요소
- Composable / XML View: 실제 UI 그리기
- ViewModel: StateFlow/LiveData로 상태 노출, 입력 메서드 제공
// XML + Kotlin 예시
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collect { state ->
// 화면 업데이트
}
}
}
// Jetpack Compose 예시
val state by viewModel.uiState.collectAsStateWithLifecycle()
공식 권장사항
“명확하게 정의된 UI 레이어를 사용합니다.” (적극 권장됨)
“UI 레이어는 화면에 애플리케이션 데이터를 표시하고 사용자 상호작용의 기본 지점으로 기능합니다.”
“단일 활동 애플리케이션을 사용합니다.” (권장됨)

3.2 데이터 레이어
- 역할: 비즈니스 로직 · 데이터 생성·저장·변경 규칙 포함
- 구성 요소
- Repository: 애플리케이션 데이터의 SSOT, Flow<T> 등으로 노출
- DataSource: Room DB, Retrofit API, DataStore, SharedPreferences, 센서 제공자 등
class MoviesRepository(
private val remote: MoviesApi,
private val local: MoviesDao
) {
fun getPopularMovies(): Flow<List<Movie>> = flow {
val cache = local.getAll()
if (cache.isEmpty()) {
val fresh = remote.fetchPopular()
local.insertAll(fresh)
emit(fresh)
} else {
emit(cache)
}
}
}
공식 권장사항
“명확하게 정의된 데이터 레이어를 사용합니다.” (적극 권장됨)
“데이터 레이어는 저장소를 사용하여 애플리케이션 데이터를 노출해야 합니다.” (적극 권장됨)
“코루틴 및 흐름을 사용합니다.” (적극 권장됨)

3.3 도메인 레이어 (Optional)
- 대규모 앱에서 권장
- UseCase / Interactor: 여러 ViewModel에서 재사용 가능한 순수 비즈니스 로직 캡슐화
class GetUserProfileUseCase(
private val userRepo: UserRepository
) {
suspend operator fun invoke(userId: String): User =
userRepo.fetchProfile(userId)
}
공식 권장사항: “도메인 레이어를 사용합니다.” (큰 앱에 권장됨)

4. 종속성 관리
- 의존성 주입(DI)
- 생성자 주입 우선
- Hilt 사용 권장 (Scope, ViewModelInjection, WorkManager 통합 등)
- 서비스 로케이터: 메인테이너·테스트 용도로 제한 사용
공식 권장사항
“종속 항목 삽입을 사용합니다.” (적극 권장됨)
“필요한 경우 구성요소로 범위를 지정합니다.” (적극 권장됨)
“Hilt를 사용합니다.” (권장됨)
5. ViewModel 상세 권장사항
- Context·Activity 참조 금지 → Pure Kotlin 클래스 유지
- viewModelScope + Flow / suspend 활용
@HiltViewModel
class MyViewModel @Inject constructor(
private val repo: MoviesRepository
): ViewModel() {
val moviesState: StateFlow<UiState<List<Movie>>> =
repo.getPopularMovies()
.map { UiState.Success(it) as UiState<List<Movie>> }
.stateIn(
viewModelScope,
SharingStarted.WhileSubscribed(5_000),
UiState.Loading
)
fun onRefresh() {
viewModelScope.launch { /* 새로고침 로직 */ }
}
}
- 화면 단위(Fragment/Activity/Composable)에서만 사용
- AndroidViewModel 대신 ViewModel + DI
공식 권장사항
“AAC ViewModel을 사용합니다.” (적극 권장됨)
“ViewModel은 Android 수명 주기에 구애받지 않아야 합니다.” (적극 권장됨)
“UI 상태를 노출합니다.” (권장됨)
6. 수명 주기 & 코루틴
- onResume/onPause 직접 오버라이드 금지 → repeatOnLifecycle / DefaultLifecycleObserver 사용
// DefaultLifecycleObserver 예시
viewLifecycleOwner.lifecycle.addObserver(object : DefaultLifecycleObserver {
override fun onResume(owner: LifecycleOwner) { /*...*/ }
override fun onPause(owner: LifecycleOwner) { /*...*/ }
})
- Compose: LaunchedEffect(Unit) / collectAsStateWithLifecycle()
공식 권장사항:
“수명 주기 인식 UI 상태 컬렉션을 사용합니다.” (적극 권장됨)
7. 테스트 권장사항
- 적극 권장
- ViewModel 단위 테스트 (StateFlow 값 검증)
- Repository/DataSource 단위 테스트 (Fake DB/API)
- UI 탐색(Integration) 테스트 (Navigation 회귀 방지)
- Fake 더블 선호 → 유지보수성·가독성↑
공식 권장사항:
“모의 테스트보다 가짜 테스트를 선호합니다.” (적극 권장됨)
“StateFlow를 테스트합니다.” (적극 권장됨)
8. 모델 설계 & 네이밍 컨벤션
- 레이어별 모델
- 네트워크 DTO → 내부 도메인 모델 → UI State 모델
- 네이밍
- 메서드: 동사형 (submitOrder())
- 속성: 명사형 (currentUser)
- 스트림: getXxxStream() (getUsersStream(): Flow<List<User>>)
- 인터페이스 구현: DefaultXxxRepository / FakeXxxRepository
공식 권장사항: “복잡한 앱에서는 레이어별 모델을 만듭니다.” (권장됨)
9. 그 외 추가 권장사항
- 앱 진입점(Activity/Service 등)에 데이터 저장 금지
- 모듈 경계 명확히: 공개 API만 최소 노출
- UI 구성요소 테스트: Composable Preview, Espresso
- 오프라인 퍼스트: 로컬 캐시 활용
공식 권장사항:
“앱 구성요소에 데이터를 저장합니다.” (선택사항)
“각 모듈에서 가능하면 적게 노출합니다.” (선택사항)
참고
앱 아키텍처 가이드 | App architecture | Android Developers
이 페이지는 Cloud Translation API를 통해 번역되었습니다. 앱 아키텍처 가이드 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 이 가이드에는 고품질의 강력한
developer.android.com
Android 아키텍처 권장사항 | Android Developers
이 페이지는 Cloud Translation API를 통해 번역되었습니다. Android 아키텍처 권장사항 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 이 페이지에서는 여러 아키
developer.android.com
'Android > Study' 카테고리의 다른 글
| [Android] Orbit Multiplatform ViewModel, ComposeUI, Test 탐구하기 (0) | 2025.07.05 |
|---|---|
| [Android] Orbit Multiplatform 개요와 Core 탐구하기 (0) | 2025.07.03 |
| [Jetpack Compose로 개발하는 안드로이드 UI] 4장. UI 요소 배치 (0) | 2025.05.13 |
| [Jetpack Compose로 개발하는 안드로이드 UI] 3장. 컴포즈 핵심 원칙 자세히 알아보기 (0) | 2025.05.07 |
| [Jetpack Compose로 개발하는 안드로이드 UI] 2장. 선언적 패러다임 이해 (0) | 2025.04.18 |