Toast 내부 구조와 Context 의존성
Toast 내부 구조와 Context 의존성
안드로이드의 Toast는 가장 흔하게 사용되는 UI 컴포넌트 중 하나이지만, 내부 아키텍처를 들여다보면 안드로이드 프레임워크가 윈도우, 시스템 서비스, 스레딩을 관리하는 방식에 대한 핵심 개념들이 드러납니다. Toast는 단순한 텍스트 팝업이 아닙니다. WindowManager, INotificationManager, 그리고 Looper/Handler 메시징 시스템과 상호작용해야 하는 시스템 관리형 윈도우입니다. Toast가 왜 Context 매개변수를 필요로 하는지, 왜 백그라운드 스레드에서 표시할 수 없는지를 이해하면 안드로이드의 핵심 설계 원칙을 깊이 파악할 수 있습니다. 이번 면접 질문을 통하여 아래 내용들을 학습하실 수 있습니다.
Toast생명주기에서Context가 수행하는 세 가지 역할, 즉 시스템 서비스 접근, 시스템 리소스 해석, 레이아웃 인플레이션에 대해 설명할 수 있습니다.WindowManager와INotificationManager가 어떻게 협력하여Toast윈도우를 표시하고 제거하는지 설명할 수 있습니다.Looper가 없는 스레드에서Toast를 생성했을 때 발생하는 크래시 경로를 추적할 수 있습니다.- 안드로이드 스레딩 모델에서
Looper,Handler,MessageQueue사이의 관계를 파악할 수 있습니다. Handler나 코루틴 디스패처를 사용하여 백그라운드 스레드에서Toast를 올바르게 표시하는 패턴을 적용할 수 있습니다.
Toast 생성 과정에서 Context의 역할
Toast.makeText(context, text, duration)을 호출할 때, Context 매개변수는 단순한 형식적 인자가 아닙니다. 안드로이드 프레임워크의 세 가지 핵심 기능에 접근하기 위한 관문 역할을 합니다. 면접에서 이 질문을 받으셨을 때 단순히 "Context가 필요하다"는 수준을 넘어서, 아래에서 설명하는 세 가지 구체적인 역할을 명확하게 구분하여 답변하시면 좋은 인상을 남기실 수 있습니다.
첫 번째이자 가장 중요한 역할은 시스템 서비스 접근입니다. Toast는 현재 Activity의 뷰 계층 구조 위에 렌더링되는 독립적인 플로팅 윈도우입니다. 안드로이드에서 모든 윈도우 관리는 system_server 프로세스에 존재하는 시스템 서비스인 WindowManagerService가 담당합니다. Toast는 context.getSystemService(WindowManager.class)를 통해 WindowManager 프록시를 얻고, ToastPresenter가 이를 사용하여 addView()와 removeView()를 호출합니다. Context가 없으면 Toast는 윈도우 시스템에 접근할 수 있는 채널 자체가 존재하지 않으므로, 화면에 아무것도 그릴 수 없습니다.
또한 Context는 내부적으로 getService() 호출을 통해 INotificationManager에 대한 접근도 제공합니다. Toast.show() 메서드는 이 Binder IPC 프록시를 가져와서 시스템 전체 Toast 큐에 해당 Toast를 등록하며, 이 과정에서 애플리케이션 프로세스에서 system_server로의 프로세스 경계를 넘는 통신이 이루어집니다.
두 번째 역할은 시스템 수준 리소스 해석입니다. Toast의 기본 위치, gravity, 오프셋 값은 하드코딩되어 있지 않습니다. 이 값들은 디바이스 제조사가 커스터마이즈할 수 있는 시스템 리소스로 정의되어 있습니다. Toast 생성자는 context.getResources().getDimensionPixelSize(...)와 context.getResources().getInteger(...)를 통해 toast_y_offset이나 config_toastDefaultGravity 같은 값을 읽어 옵니다. 덕분에 특정 디바이스에서 표시되는 모든 Toast 메시지가 해당 OEM의 디스플레이 설정을 일관되게 따르게 됩니다.
Context는 디스플레이 밀도와 구성 정보도 함께 전달합니다. 치수 리소스를 해석할 때 Resources 객체는 Context의 디스플레이 메트릭스를 사용하여 밀도 독립적 값(dp)을 물리적 픽셀로 변환합니다. 예를 들어, Toast 오프셋 64dp는 mdpi 화면과 xxxhdpi 화면에서 서로 다른 픽셀 수로 매핑됩니다.
세 번째 역할은 레이아웃 인플레이션입니다. 표준 텍스트 Toast는 TextView를 포함하는 미리 정의된 XML 레이아웃(transient_notification.xml)을 사용합니다. 이 XML을 View 계층 구조로 변환하려면 LayoutInflater.from(context)를 통해 LayoutInflater를 얻어야 합니다. 인플레이터는 테마 속성과 스타일 참조를 해석하기 위해 Context를 필요로 합니다. 가령, style="?android:attr/toastTextStyle"을 해석하려면 Context에 연결된 테마 계층 구조를 탐색해야 합니다.
Toast 표시 파이프라인: WindowManager와 INotificationManager의 협력
toast.show()를 호출한 시점부터 실제로 화면에 픽셀이 그려지기까지의 과정에는 프로세스 경계를 넘어 두 개의 시스템 서비스가 협력하는 구조가 관여합니다. 이 파이프라인을 이해하면 안드로이드가 왜 이렇게 복잡한 구조를 채택했는지에 대한 통찰을 얻으실 수 있습니다.
show()가 호출되면 Toast는 즉시 화면에 뷰를 추가하지 않습니다. 대신 시스템 서버의 NotificationManagerService를 통해 접근하는 INotificationManager 서비스에 IPC 호출을 수행합니다. Toast는 이 서비스에 두 가지 정보를 전달하며 등록합니다.