Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Android는 어떻게 화면을 그릴까?

Android는 어떻게 화면을 그릴까?

2025.04.05
Build With AI 2025

Avatar for DavidKwon7

DavidKwon7

April 05, 2025
Tweet

More Decks by DavidKwon7

Other Decks in Technology

Transcript

  1. ◼ XML(eXtensible Markup Language) 은 UI를 정의하는 마크업 언어 ◼

    Android에서는 .xml 파일로 UI를 설계하고, 이를 setContentView()를 통해 분리된 환경에서 화면 구현 XML 이란
  2. 장점 • UI와 로직이 분리되어 있어 가독성이 좋음 • ConstraintLayout,

    LinearLayout 등을 활용해 UI를 쉽게 배치 가능 • Android Studio의 Layout Editor에서 미리보기 제공 단점 • XML과 코드(findViewById())를 연결해야 함 → 번거로움 • RecyclerView 등 동적인 UI 구성 시 코드가 복잡해짐 XML 장점 / 단점
  3. ◼ Jetpack Compose는 Kotlin 기반의 선언형 (Declarative) UI 프레임워크 ◼

    XML 없이 코드에서 직접 UI를 작성 ◼ React, Flutter와 비슷한 개념으로 State 기반 UI 업데이트 지원 Jetpack Compose
  4. @Composable fun MyScreen() { Column { Text(text = "안녕하세요!") Button(onClick

    = { /* 클릭 이벤트 */ }) { Text(text = "클릭하세요") } } }
  5. 장점 • XML 없이 코드에서 직접 UI를 정의 가능 •

    효율적인 UI 업데이트 (필요한 부분만 다시 그림) • 쉬운 컴포넌트 재사용 및 공유 단점 • 기존 View 시스템과 완전히 다르므로 학습 필요 • 커뮤니티 리소스가 XML에 비해 상대적으로 적음 Compose 장점 / 단점
  6. ◼ setContentView() 호출 시, LayoutInflater.inflate()를 내부적으로 호출 ◼ LayoutInflater가 XML을

    읽고, View 객체 생성 ◼ViewGroup(부모 view)과 자식 view들이 계층 구조 (Tree)로 메모리에 로드됨 XML Parsing
  7. View Group, View • View : 위젯이라 하며 Button, TextView

    등을 예로 들 수 있다. • View Group : View를 여러개 담을 수 있다. (LinearLayout, ConstraintLayout..)
  8. <?xml version="1.0"encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:id="@+id/text" android:layout_width="wrap_content"

    android:layout_height="wrap_content" android:text="Hello,I am a TextView"/> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello,I am a Button"/> </LinearLayout> View Group View View
  9. ◼ View의 크기를 결정하는 기능 수행 ◼ 각 뷰가 자신에게

    주어진 크기를 기준으로 크기를 결정 ◼ 부모 ViewGroup이 자식 View의 제약조건 (MeasureSpec)을 설정 onMeasure()
  10. ◼ MeasureSpec.EXACTLY : 부모가 자식의 정확한 크기를 결정했습니다. 자식 View가

    얼마나 큰지 관계없이 지정된 크기(경계)가 주어집니다. ◼ MeasureSpec.AT_MOST : 자식은 지정된 크기까지 원하는만큼 커질 수 있습니다. ◼ MeasureSpec.UNSPECIFIED : 부모가 자식에게 어떤 제약도 부과하지 않았습니다. 원하는 크기가 될 수 있습니다. onMeasure()
  11. ◼ View의 위치를 결정하기 위해 onLayout() 메서드 호출 ◼ onMeasure()

    단계에서 결정된 크기를 기반으로 View의 화면상 위치 설정 ◼ 각 View가 부모로부터 위치 정보를 받아 배치됨 ◼ ViewGroup이 onLayout()을 호출하여 자식 View의 위치를 결정 onLayout()
  12. ◼ Canvas 객체를 이용해 View를 그리는 단계 ◼ View의 상태가

    변경되거나 화면을 다시 그려야 하는 경우에 invalidate() 메서드를 호출하여 onDraw() 메서드를 다시 호출할 수 있습니다. onDraw()
  13. ◼ Window는 뭔가를 그릴 수 있는 창이며, WindowManager를 통해 Window를

    관리할 수 있습니다. ◼ Window는 독립적인 Surface를 가지고 있습니다. Window
  14. ◼ Surface는 Window에 표시될 그래픽 데이터를 저장할 수 있는 메모리

    영역을 제공 ◼ App이 Surface에 직접 그림을 그리고, 이를 SurfaceFlinger가 화면에 합성 Surface
  15. ◼ Bitmap에 그림을 그릴 수 있는 도구(렌더링 엔진) ◼ Surface를

    잠그면 Canvas 객체를 얻을 수 있으며, 이 Canvas를 사용하여 Surface의 드로잉 버퍼에 그림을 그릴 수 있습니다. Canvas
  16. ◼ Surface의 Buffer를 잠그고, 그림을 그릴 수 있는 Canvas 객체를

    반환. ◼ Buffer를 잠그는 이유는 여러 스레드에서 동시에 버퍼에 접근하여 데이터를 변경하는 것을 방지하기 위함 Lock Canvas
  17. ◼ lockCanvas()로 잠근 드로잉 버퍼를 잠금 해제하고, 변경된 내용을 SurfaceFlinger에

    전달하여 화면에 표시되도록 한다. ◼ unlockAndPost()를 호출하기 전까지 Surface에 그린 내용은 화면에 표시되지 않습니다. ◼ Buffer의 잠금을 해제하면, 다른 스레드에서 드로잉 버퍼에 접근할 수 있습니다. UnlockAndPost
  18. val surfaceHolder = surfaceView.holder val paint = Paint() paint.color =

    Color.WHITE paint.textSize = 50f val canvas = surfaceHolder.lockCanvas() if (canvas != null) { try { canvas.drawColor(Color.BLACK) canvas.drawText("Hello", 100f, 100f, paint) } finally { surfaceHolder.unlockCanvasAndPost(canvas) } } Canvas에 그리기 수행 그린 내용을 화면에 표시
  19. 동작 방식 Window 생성하고, Window는 자체 Surface 생성 Surface 잠그면

    Canvas 객체를 얻을 수 있습니다 Canvas를 사용하여 View 계층 구조를 따라가며 UI를 그립니다 그리기 작업이 완료되면 Surface를 잠금 해제 SurfaceFlinger는 게시된 버퍼를 사용하여 화면 합성
  20. displayList ◼ View에 변경이 발생하면 View-ViewGroup-Root View-View까지 내려와야하는 과정이 있었고,

    이는 매우 비효율적이었다. 이러한 문제점을 해결하기 위해서 displayList 등장. ◼ UI 관련 그래픽 데이터를 저장해둔 후, 변경이 발생하면 바로 리스트를 확인해서 효율적으로 변경에 대응할 수 있다는 이점 존재.
  21. displayList ◼ View의 onDraw() 메서드가 호출되면 View가 그려진다. 이때 그려지는

    모든 정보는 displayList에 기록. ◼ View의 내용이 변경되지 않았으면, 이전에 생성된 DisplayList를 재사용, 변경(invalidate)되었으면 새로운 displayList 생성 ◼ displayList에 기록된 view 관련 데이터는 GPU로 전송
  22. Rasterization (래스터화) ◼ UI 요소를 그릴 때 직선, 곡선, 도형

    등 백터 데이터를 픽셀 정보(래스터 이미지)로 변환하여 디스플레이로 출력하는 과정 ◼ GPU에서 렌더링 된 데이터는 BufferQueue를 통해 SurfaceFlinger라는 시스템 서비스로 전달됩니다.
  23. SurfaceFlinger ◼ 생산자가 버퍼를 전달하면 SurfaceFlinger는 모든 요소를 디스플레이에 합성해야

    합니다. ◼ V-Sync와 맞춰 디스플레이에 출력 ◼ Hardware Composer(HWC)와 협력하여 디스플레이로 출력
  24. HWC (hardware composer) ◼ UI를 렌더링하고 이를 BufferQueue를 통해 SurfaceFlinger에

    전달 ◼ HWC는 하드웨어 수준에서 화면 합성을 수행 ◻ 여러 레이어(UI, 네비게이션바, 상태바 ..)를 하나의 최종 이미지로 합성 ◻ GPU보다 전력 효율이 좋은 전용 디스플레이 하드웨어를 활용하여 합성 작업을 수행 ◼ HWC는 한정된 resource를 가지고 있는 Android에서 GPU의 부담을 줄이고, 디스플레이 하드웨어를 활용하여 최적의 성능을 제공 가능
  25. Project Butter • Android 모바일 운영 체제의 속도와 반응성을 높이기

    위한 Google의 프로젝트 (Android 4.1 Jelly Bean(2012년)에 처음 소개) • UI의 부드러움과 반응성을 개선하는데 초점
  26. V-Sync 적용 • 화면 주사율(60Hz)에 맞춰 UI를 렌더링하여 부드러운 애니메이션

    제공 • 화면 끊김(Jank) 방지 Triple Buffering 도입 • Double Buffering -> Triple Buffering • UI 렌더링 시 GPU가 다음 프레임을 준비하는 동안 CPU가 UI 로직을 동시에 처리가 가능해짐 • Frame Drop 문제 해결 Project Butter
  27. 터치 반응 속도 향상 V-Sync와 동기화하여 반응 속도 증가 렌더링

    성능 향상 • GPU 하드웨어 가속을 모든 UI 애니메이션에 적용 • 기존에는 일부 UI 요소만 하드웨어 가속을 사용했지만, Project Butter 이후 전체 UI가 GPU 가속 활용 Project Butter
  28. V-Sync(수직동기화) ◼ GPU의 Rendering Rate(fps)와 Device Presenting Rate(hz) 간의 간극이

    있을 때 조정해주는 역할을 수행 ◼ V-Sync는 디스플레이가 화면을 업데이트하는 시점을 나타내는 신호입니다. ◼ 이를 통해 화면 Tearing이나 Frame Drop없이 부드러운 화면 표시를 보장
  29. Choreographer ◼ Project Butter에서 도입 ◼ V-Sync 신호에 맞춰 UI가

    일정한 프레임 속도로 렌더링되도록 보장하는 역할
  30. 렌더링 작업 스케줄링 애니메이션, UI 업데이트가 요청되면 V-Sync 신호에 맞춰

    적절한 시점에 실행되도록 스케줄링 V-Sync 동기화 • V-Sync 신호에 맞춰 App의 렌더링 작업을 실행 • 이를 통해 부드러운 화면 구성을 얻을 수 있다. 콜백 등록 • Choreographer에 콜백을 등록하여 V-Sync 신호가 발생할 때 특정 작업을 수행하도록 설정 가능 • 이를 통해 애니메이션, UI 업데이트, 그리기 작업 등을 V-Sync에 맞춰 실행 가능 Choreographer
  31. Buffering ◼ Buffer는 GPU가 그린 화면을 임시 저장하는 메모리 공간

    ◼ Buffering은 UI를 부드럽게 그리기 위해 한 번에 한 프레임씩 준비하는 것이 아니라 백그라운드에서 미리 프레임을 준비해서 표시하는 방식을 의미
  32. Double Buffering 개념 • 두 개의 버퍼 • Front Buffer

    : 현재 디스플레이에 출력 중인 프레임 • Back Buffer : 다음 프레임을 준비하는 버퍼 동작 방식 • GPU가 Back Buffer에서 새 프레임을 그림 • 프레임이 완료되면 Front Buffer와 교체 • 디스플레이는 새로운 Front Buffer를 출력
  33. Triple Buffering 개념 • 세 개의 버퍼 • Front Buffer

    : 출력 중인 프레임 • Back Buffer1 : 렌더링이 끝난 프레임 • Back Buffer2 : 렌더링 중인 프레임 동작 방식 • GPU가 Back Buffer에서 새 프레임을 그림 • 디스플레이가 준비되면 Back Buffer와 Front Buffer 교체 • 이전 Front Buffer는 Back Buffer로 변경 • 기존에 남아있던 Back Buffer에 다음 프레임 렌더링
  34. Android에서 XML, Jetpack Compose로 작성된 코드는 parsing 진행 parsing된 데이터들은

    displayList에 저장이 되고 래스터화 BufferQueue를 통해 SurfaceFlinger에서 합성된 후 화면에 출력 결론 Android 그래픽 GPU 렌더링 속도 및 오버로드 검사