
안드로이드 앱 구조 판단 기준이 없으면 코드를 봐도 이름만 많고, 왜 그렇게 나뉘어 있는지 잘 안 보입니다. 이번 글에서는 안드로이드 앱 구조를 볼 때 무엇부터 판단해야 할까를 초보자 기준으로 정리합니다. UI, 상태, 생명주기, 비동기 작업, 데이터 흐름, 경계를 어떤 순서로 보면 좋은지 시리즈 마지막 편에서 한 번에 묶어보겠습니다.
안드로이드 앱 구조 판단 기준
초보자에게 가장 쉬운 출발점은 패턴 이름을 맞히는 일이 아닙니다. 먼저 UI, 상태, 생명주기, 비동기 작업, 데이터 흐름, 경계를 순서대로 보는 편이 훨씬 낫습니다. 안드로이드 앱 구조는 클래스 이름보다 책임과 흐름으로 읽을 때 더 잘 보이기 때문입니다.
- 이 화면의 UI는 무엇을 보여주는가
- 그 화면 상태는 어디에 머무는가
- 그 상태는 생명주기 변화에서 어떻게 버티는가
- 비동기 작업은 누가 시작하고 누가 끝내는가
- 데이터는 어느 방향으로 흐르는가
- 계층 경계가 어디서 섞이는가

UI
제일 먼저 볼 것은 UI입니다. 여기서 말하는 UI는 예쁜 화면이 아니라 이 화면이 지금 어떤 상태를 보여주는가입니다. 검색 화면이라면 로딩 중인지, 결과를 보여주는지, 빈 결과인지, 에러를 보여주는지부터 읽어야 합니다.
- UI는 사용자 이벤트를 받는다
- UI는 상태를 읽고 그린다
- UI가 직접 상태를 오래 붙잡고 데이터 작업까지 다 하면 구조가 무거워지기 쉽다
UI는 일을 많이 하는 자리보다 상태를 보여주는 자리에 가깝습니다. 이 기준으로 보면 Fragment나 Activity가 왜 점점 무거워지는지도 빨리 보입니다.
상태
그다음은 상태입니다. 모든 값이 같은 종류는 아닙니다. 초보자라면 먼저 화면 전체를 설명하는 상태와 특정 View 하나에 가까운 작은 상태를 구분하는 것만으로도 구조가 훨씬 쉬워집니다.
- 화면 상태: 로딩 여부, 결과 목록, 에러 메시지, 현재 선택된 필터
- 작은 UI 상태: 포커스, 일시적인 펼침 여부, 스크롤 위치, 입력 중인 임시 값
여기서 던질 질문은 하나입니다. 이 값이 바뀌면 화면의 의미가 달라지는가. 달라진다면 화면 상태일 가능성이 크고, 이런 값은 보통 ViewModel 같은 state holder 쪽이 더 자연스럽습니다. 반대로 특정 View 하나의 일시적 반응에 가깝다면 굳이 위로 끌어올리지 않아도 됩니다.
생명주기
상태를 본 다음에는 생명주기를 봐야 합니다. 안드로이드에서는 화면이 계속 살아 있지 않습니다. 회전할 수도 있고, 뒤로 갈 수도 있고, 잠깐 가려졌다가 다시 돌아올 수도 있습니다. 그래서 구조를 볼 때는 항상 상태와 작업의 수명이 어디에 붙어 있는지 같이 봐야 합니다.
- 이 상태는 화면이 다시 만들어져도 유지되어야 하는가
- 이 작업은 화면이 안 보일 때도 계속 돌아가야 하는가
- 이 수집은 화면이 보일 때만 살아 있어야 하는가
이 질문을 빼면 화면이 사라졌는데도 이전 Fragment가 결과를 그리려 하거나, 회전 후 상태가 갑자기 초기화되는 문제가 생기기 쉽습니다. 즉 생명주기는 부가 지식이 아니라 구조의 수명표에 가깝습니다. 더 자세한 흐름은 생명주기를 알아야 설계가 쉬워지는 이유에서 먼저 연결해서 볼 수 있습니다.
비동기 작업
그다음은 비동기 작업입니다. 여기서는 코루틴 문법보다 먼저 누가 작업을 시작하는가를 봐야 합니다. 초보자가 자주 꼬이는 구조는 화면 코드가 요청 시작, 로딩 처리, 결과 표시를 한 번에 다 떠안는 경우입니다.
class SearchFragment : Fragment() {
fun onSearchClicked(query: String) {
showLoading(true)
lifecycleScope.launch {
val items = repository.search(query)
showLoading(false)
showItems(items)
}
}
}처음에는 단순해 보여도, 조금만 요구사항이 늘어나면 로딩 상태를 누가 기억하는지, 실패 처리를 누가 맡는지, 재생성 뒤 흐름이 어떻게 이어지는지가 금방 흐려집니다. 이럴 때는 코루틴을 어디서 쓰느냐보다 아래 질문이 더 중요합니다.
- 이 작업은 화면 단위 작업인가
- 결과를 화면 상태로 바꿔야 하는가
- 화면이 사라지면 멈추거나 정리되어야 하는가
이 질문에 답해보면 보통 UI는 이벤트 전달, ViewModel은 작업 시작과 상태 변경, Repository는 실제 데이터 처리라는 흐름이 더 자연스럽게 보입니다. 바로 앞 글인 안드로이드에서 비동기 작업은 구조와 어떻게 연결될까와도 이어집니다.
데이터 흐름
비동기 작업까지 봤다면 이제 데이터 흐름을 봅니다. 좋은 구조는 값이 어디서 왔고 어디서 바뀌는지 읽기 쉽습니다. 즉 데이터 흐름이 한 방향으로 보일수록 구조를 이해하기 쉬워집니다.
- 사용자가 버튼을 누른다
- UI가 이벤트를 전달한다
- ViewModel이 상태를 바꾼다
- Repository가 데이터를 가져온다
- ViewModel이 새 상태를 만든다
- UI가 그 상태를 그린다
반대로 UI가 Repository를 직접 부르거나, Repository가 UI 메시지까지 직접 만들거나, 여러 곳에서 같은 값을 제각각 수정하기 시작하면 구조는 빠르게 흐려집니다. Android Developers가 Guide to app architecture와 Architecture recommendations에서 single source of truth와 unidirectional data flow를 강조하는 이유도 여기에 있습니다.
값의 주인과 흐름이 보이면 구조도 같이 보입니다. 상태 위치가 헷갈린다면 화면 상태는 어디에 두는 게 맞을까를 함께 보면 더 잘 연결됩니다.
경계
마지막은 경계입니다. UI, ViewModel, Repository라는 이름을 외우는 것보다 어디서 경계가 무너졌는지를 보는 눈이 생기면 코드 읽기가 훨씬 빨라집니다.
- Fragment가 네트워크 호출, 상태 보관, 에러 문구 결정까지 다 한다
- ViewModel이 View 참조나 Context 의존성을 너무 많이 안고 있다
- Repository가 토스트 문구나 화면 전환까지 신경 쓴다
- 여러 계층이 같은 mutable 값을 함께 바꾼다
경계가 잘 보이지 않을 때는 아주 단순하게 생각하면 됩니다. UI는 보여주기, ViewModel은 화면 상태와 흐름 정리, Repository는 데이터 처리입니다. 입문 단계에서는 이 경계만 분명해도 구조가 많이 안정됩니다. ViewModel의 자리를 다시 정리하고 싶다면 ViewModel은 왜 필요할까를 함께 읽어보면 좋습니다.
빠른 진단
코드를 처음 볼 때는 긴 설명보다 짧은 질문이 더 도움이 됩니다. 아래 질문으로 먼저 진단해보면 좋습니다.
- 이 화면은 지금 어떤 상태를 보여주는가
- 그 상태의 주인은 누구인가
- 화면이 다시 만들어져도 유지되어야 하는 값은 무엇인가
- 비동기 작업은 누가 시작하는가
- 결과는 어디서 화면 상태로 바뀌는가
- 데이터는 한 방향으로 읽히는가
- UI, ViewModel, Repository 경계가 섞이지 않았는가
이 질문에 답이 잘 안 나오면, 아직 구조가 복잡한 것이 아니라 구조를 읽는 기준이 부족한 것일 가능성이 큽니다. 이 시리즈의 흐름을 다시 연결하고 싶다면 안드로이드 앱은 어떻게 돌아갈까부터 비동기 작업 편까지 순서대로 다시 보면 구조가 더 또렷해집니다.
마무리
안드로이드 앱 구조를 볼 때 처음부터 패턴 이름을 맞히려 할 필요는 없습니다. 먼저 UI를 보고, 상태를 보고, 생명주기를 보고, 비동기 작업을 보고, 데이터 흐름을 보고, 마지막으로 경계를 보면 됩니다. 이 여섯 가지가 한 번에 완벽하게 보이지 않아도 괜찮습니다. 중요한 것은 코드를 볼 때 계속 같은 질문을 던지는 것입니다. 그 질문이 쌓이면 구조가 보이기 시작합니다.
공식 기준은 Guide to app architecture, UI layer, Architecture recommendations, ViewModel overview, Activity lifecycle 문서를 같이 보면 더 분명해집니다.