
안드로이드 개발을 하다 보면 XML에 View를 선언하고 setContentView() 한 줄만 호출해도 화면이 그려집니다.
(물론 요즘은 XML 보단 Compose를 많이 사용하는 추세이지만, XML을 알고 Compose를 알면 더 좋을 것 같아서 XML의 과정을 먼저 정리해보려 합니다.)
하지만 막상 XML이 실제 View 객체가 되고, 화면에 그려지기까지의 흐름을 정확히 설명하려고 하면 애매해지는 경우가 많습니다.
이번 글에서는 XML → View 객체 → Measure → Layout → Draw 이 전체 과정을 흐름 위주로 정리해보겠습니다.
1️⃣ setContentView()가 호출되면 무슨 일이 벌어질까?
Activity에서 가장 흔히 보는 코드부터 시작합니다.
setContentView(R.layout.activity_main)
이 한 줄이 호출되면 내부적으로는 다음 작업이 일어납니다.
- XML 리소스를 읽어온다
- XML을 파싱한다
- View 객체 트리를 생성한다
- DecorView에 붙인다
이 모든 작업의 중심에 있는 게 바로 LayoutInflater입니다.
2️⃣ LayoutInflater : XML을 View로 바꾸는 공장
LayoutInflater의 역할은 단순합니다.
XML 파일을 실제 View 객체 트리로 변환
val view = LayoutInflater.from(context) .inflate(R.layout.activity_main, parent, false)
inflate 내부에서 하는 일은 다음과 같습니다.
- XML 태그를 한 줄씩 읽기
- 태그 이름으로 View 클래스 찾기
- Reflection으로 View 생성자 호출
- layout_width, layout_height 같은 속성 적용
- 부모-자식 관계 설정
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
예를 들어 위와 같은 코드의 경우, 내부적으로는 아래와 같은 느낌이라고 볼 수 있습니다.
TextView(context, attrs)
즉, XML은 View 설계도가 되고, LayoutInflater는 설계도를 실제 객체로 찍어내는 공장이라고 비유해 볼 수 있습니다!
이렇게 보니 조금 더 쉽게 다가오죠?
3️⃣ View 트리는 어디에 붙을까? (DecorView)
그러나 이때, inflate로 만들어진 View 트리는 곧바로 화면에 그려지지 않습니다.
구조는 대략 아래와 같습니다
DecorView
└─ LinearLayout
├─ ActionBar
└─ ContentView (setContentView로 넣은 레이아웃)
- DecorView는 윈도우의 루트 View
- 상태바, 네비게이션바, 액션바까지 포함
우리가 만든 레이아웃은 DecorView 안쪽 Content 영역에 삽입됩니다.
그리고 View가 생겼다고 바로 그려지는 것 또한 아닙니다!
View가 화면에 보이려면 반드시 다음 3단계를 거칩니다.
Measure → Layout → Draw
이걸 흔히 View Rendering Pipeline이라고 합니다.
5️⃣ Measure 단계 : “이 View, 크기가 얼마야?”
measure() 단계에서는 각 View가 자신의 크기를 계산합니다.
이때 중요한 것들이 있습니다.
- layout_width, layout_height
- wrap_content, match_parent
- 부모 View가 준 MeasureSpec
onMeasure(widthMeasureSpec, heightMeasureSpec)
부모가 자식에게 “이 안에서 크기 정해” 하고 제약을 전달합니다.
그럼 이 단계에서 measuredWidth / measuredHeight가 결정됩니다.
6️⃣ Layout 단계 : “어디에 놓을까?”
크기가 정해졌다면 이제 위치를 정해야 합니다.
onLayout(changed, l, t, r, b)
- 부모 View가 자식 View들을 순회
- 각 View의 좌표(left, top, right, bottom) 결정
크기는 Measure을 의미하고, 위치는 Layout을 의미하게 됩니다.
7️⃣ Draw 단계 – “마지막 그리기 단계”
드디어 마지막으로 실제 화면에 그리는 단계입니다.
onDraw(canvas: Canvas)
여기서 배경, 텍슽, 이미지, 커스텀 드로잉 등 모든 픽셀이 그려지게 됩니다.
그리고 이 단계가 끝나면 우리가 흔히 보는 화면이 됩니다.
마지막으로 총 정리를 해보자면 아래와 같습니다!
XML
↓
LayoutInflater (XML 파싱)
↓
View 객체 트리 생성
↓
DecorView에 attach
↓
Measure (크기 계산)
↓
Layout (위치 계산)
↓
Draw (화면에 그림)
코드를 짤 때에는 `setContentView()` 함수 하나로 간편하게 화면을 그렸었는데, 화면이 그려지는 과정을 자세히 들여다보니
모르고 있던 디테일들이 많은 것 같습니다.
XML은 단순한 UI 선언처럼 보이지만, 그 뒤에는 꽤 많은 단계와 규칙이 숨어 있습니다.
이 흐름을 한 번이라도 명확히 이해하고 나면 UI 버그를 만났을 때 막연한 추측이 아니라 의심 지점부터 정확히 짚을 수 있게 되겠죠?
모든 디버깅은 기초를 알아야 정확히 할 수 있는 것 같습니다 ㅎㅎ
📚 참고
https://developer.android.com/guide/topics/ui/how-android-draws?hl=ko
Android에서 뷰를 그리는 방법 | Views | Android Developers
활동이 포커스를 받으면 레이아웃을 그리라는 요청을 받습니다. Android 프레임워크에서 그리기 절차를 처리하지만 활동에서 레이아웃 계층 구조의 루트 노드를 제공해야 합니다. 그리기는 레이
developer.android.com
https://developer.android.com/reference/android/view/View
View | API reference | Android Developers
developer.android.com
'Android' 카테고리의 다른 글
| [Android] Android 앱 아이콘을 클릭하는 순간부터 화면에 그려지기까지 (0) | 2026.03.08 |
|---|---|
| [Android] Compose가 UI를 그리기까지의 과정 (0) | 2026.02.22 |
| [Android] Mutex와 Coroutine으로 동시성 문제 해결하기 (0) | 2026.01.25 |
| [Android] Build Variant는 왜 필요할까: 안드로이드 빌드 관리하기 (0) | 2026.01.11 |
| [Android] 결제에서 Consume은 왜 필요할까? (0) | 2025.12.28 |