아주 쉽게 알아보는 뷰가 그려지기까지의 여정

2025. 10. 29. 19:27·Android

Activity의 생명주기, Fragment의 생명주기, ViewModel의 생명주기까지 안드로이드를 조금이라도 공부해 본 사람들이라면 이 내용에 대해 당연히 들어봤고 한 번쯤은 공부해 봤을 것입니다. 하지만 View의 생명주기는 어떨까요?

 

필자는 다른 컴포넌트들의 생명주기에 비해 유독 View의 생명주기가 어렵게 느껴졌기 때문에 이를 조금이라도 쉽게 풀어 소개해보고자 합니다. 먼저 View의 생명주기에 대해 알아보겠습니다. View가 화면에 보이기까지는 크게 4단계를 거칩니다

  • onAttachedToWindow() : 화면 준비 완료 !
  • onMeasure() : 내 크기는 얼마나 필요해 ?
  • onLayout() : 내 자리는 어디야 ?
  • onDraw() : 이제 그린다 !

onAttachedToWindow( )

뷰가 Window에 연결될 때 호출됩니다. 안드로이드 앱을 개발하다 보면 종종 window라는 단어를 볼 수 있습니다. 여기서 말하는 Window란 무엇일까요? 이름에서 추상적으로 드러내고 있는 것처럼 무언가를 그리기 위한 공간 정도로 예측할 수 있을 것 같습니다.

Window는 "그림을 그릴 수 있는 캔버스"입니다. 배터리, 시간 등을 표시하기 위한 Status Bar의 Window, 앱의 화면을 그리기 위한 Activity의 Window, NavigationBbar를 그리는 window 등 이 모든 것들은 windowManager에 의해 제어되고 있습니다.

onMeasure()

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)

뷰를 그릴 준비가 되었으니 이제 뷰가 얼마나 공간을 차지할지 알아야 합니다. 뷰의 크기를 계산하기 위해 onMeasure()가 호출됩니다. ViewGroup의 경우 각각의 자식 뷰에 대해 measure를 호출하여 크기를 계산합니다.

 

이때 MeasureSpec이라는 개념이 등장하게 되는데 레이아웃 측정 과정에서 부모 뷰가 자식 뷰에 크기 제약 사항을 전달하는데 사용됩니다. 쉽게 말해, 자식 뷰들이 얼마만큼의 크기를 사용할 수 있는지 제한하는 제약조건입니다. MeasureSpec엔 3가지 조건이 있습니다.

 

MeasureSpec.EXACTLY

  • 정확히 100px 써!
  • 부모가 자식에 대해 정확한 크기를 지정한 경우입니다.
  • width/height, match_parent 속성 등이 해당됩니다.

MeasureSpec.AT_MOST

  • 최대 100px까지 쓸 수 있어!
  • 부모가 자식에 대해 최대 크기를 지정한 경우입니다.
  • 자식은 지정된 크기까지 원하는 크기를 가질 수 있습니다. 

MeasureSpec.UNSPECIFIED

  • "너의 꿈을 펼쳐라"
  • 부모가 자식에 대해 제한을 두지 않은 경우입니다.

onLayout()

protected void onLayout(boolean changed, int left, int top, int right, int bottom)

이제 뷰의 크기가 모두 측정되었으니 어디에 배치할지 정해야겠죠? onLayout은 뷰들이 그려질 위치를 지정합니다.

 

onDraw()

이제 마지막으로 이전 단계에서 계산된 크기와 위치를 기반으로 뷰를 그립니다. onDraw()는 여러 번 호출될 수 있기 때문에 이 점을 염두하여 무거운 작업을 하지 않아야 합니다.

뷰 계층 구조

안드로이드 OS는 Layout XML 코드를 토대로 뷰 계층 구조 트리를 만듭니다. 이 트리는 부모 노드(ViewGroup)에서 자식 노드(View)로 이어지는 가족 관계도 같은 구조입니다. 화면을 그리기 위해 안드로이드는 이 트리를 최상위 ViewGroup에서 시작하여 하위 자식 View로 내려가며 순회합니다.

 

이 과정에서 Measure Pass(크기 측정)와 Layout Pass(위치 배치)라는 두 단계를 거치는데, 이를 합쳐 Two-Pass Process라고 부릅니다.

Double Taxation(이중 과세)

Two-Pass Process를 두 번 이상 반복하는 것을 말합니다. 이는 Layout의 복잡한 계층 구조에 의해 발생할 수 있습니다. 예를 들어 RelativeLayout을 사용하면 첫 번째 패스를 통해 각 뷰의 크기를 파악하고, 두 번째 패스에서 이 정보를 활용하여 뷰들을 상대적인 위치에 적절히 배치하기 때문에 Double Taxation이 발생합니다.

 

또한 layout_weight 속성을 사용하는 경우에도 Relative Layout과 비슷한 원리로 View들 간의 가중치를 계산해야 하기 때문에 Double Taxation이 발생합니다.

 

필자는 실제로 안드로이드를 처음 접했을 때 Relative Layout과 중첩된 LineaLayout을 사용해 화면 스크롤 시 Jank 현상이 발생했습니다. 이를 안드로이드 기기의 렌더링 성능 측정을 위한 온디바이스 툴들을 사용해 검사하고 개선해 나간 적이 있는데, 해당 내용을 토대로 우아한테크코스에서 테코톡을 발표한 영상이 있으니 관심 있으시다면 한 번쯤 보시는 것을 추천 (안)합니다.

Reference

아무나 못보는 레아의 킹왕짱 "뷰가 그려지는 과정, 뷰 성능 개선" 수업

'Android' 카테고리의 다른 글

Compose 디자인 시스템 설계하기  (0) 2026.01.22
HiltViewModel 의존성 주입 원리  (0) 2025.11.06
운영체제 메모리  (0) 2025.10.14
안드로이드에서 네트워크 상태에 따라 API를 재호출해보자  (0) 2025.09.27
Retrofit Internals - Retrofit In Coroutine  (0) 2025.06.20
'Android' 카테고리의 다른 글
  • Compose 디자인 시스템 설계하기
  • HiltViewModel 의존성 주입 원리
  • 운영체제 메모리
  • 안드로이드에서 네트워크 상태에 따라 API를 재호출해보자
빨주노초잠만보
빨주노초잠만보
  • 빨주노초잠만보
    과거의 나를 통해 미래의 나를 성장시키자
    빨주노초잠만보
  • 전체
    오늘
    어제
    • 분류 전체보기 (108)
      • 우아한테크코스 (6)
      • TEKHIT ANDROID SCHOOL (4)
      • Android Architecture (8)
      • Android (38)
      • PROJECT (11)
      • KOTLIN (10)
        • 코루틴의 정석 (3)
      • BACK END (12)
      • CS (4)
      • 컨퍼런스 (4)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    android Room
    flow
    2025 우아콘 후기
    코틀린 코루틴의 정석
    컴포즈 디자인 시스템
    Room
    Compose Typography
    MVI
    Repository Pattern
    의존성 주입
    STATEFLOW
    callbackflow
    view 생명주기
    Two pass process
    thread Context Switching
    android clean architecture
    ThrottleFirst
    Clean Architecture
    Throttle
    DataSource
    repository
    sealed class
    orbit
    retrofit call
    android view lifecylce
    안드로이드 디자인 시스템
    coroutine Context Switching
    process Context Switching
    DI
    value class
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
빨주노초잠만보
아주 쉽게 알아보는 뷰가 그려지기까지의 여정
상단으로

티스토리툴바