패스잇

모바일 개발

Android / Kotlin 면접 질문

액티비티·프래그먼트 생명주기, Intent, 레이아웃(ConstraintLayout), ViewModel과 아키텍처 컴포넌트, Jetpack Compose의 Recomposition, 백그라운드 실행 제한, 멀티 모듈 의존성. Android 면접은 API를 외웠는지보다 생명주기와 메모리·백그라운드 제약 속에서 안정적인 앱을 어떻게 만드는지를 봅니다. Kotlin 기반 안드로이드 단골 질문을 모범답안과 함께 정리했습니다.

총 21문제 · 기초 7 · 중급 7 · 심화 7 · 모범답안 포함

Android / Kotlin 면접 질문 · 기초

Q1 기초

안드로이드 액티비티의 생명주기(Lifecycle)란 무엇이며, 주요 콜백 메서드(onCreate, onStart, onResume, onPause, onStop, onDestroy)의 역할에 대해 설명해주세요.

힌트 · 액티비티의 상태 변화에 따라 호출되는 메서드들의 집합이며, 각 메서드는 특정 시점에 수행해야 할 작업을 정의합니다.

안드로이드 액티비티 생명주기는 액티비티가 생성되고 소멸될 때까지의 상태 변화 과정을 의미합니다. 각 상태 변화 시점에 맞춰 특정 콜백 메서드들이 호출되죠.

전체 모범답안 펼치기

안드로이드 액티비티 생명주기는 액티비티가 생성되고 소멸될 때까지의 상태 변화 과정을 의미합니다. 각 상태 변화 시점에 맞춰 특정 콜백 메서드들이 호출되죠.

  • onCreate(): 액티비티가 처음 생성될 때 호출됩니다. UI 초기화나 데이터 로딩 같은 초기 설정을 주로 여기서 합니다.
  • onStart(): 액티비티가 사용자에게 보여지기 직전에 호출됩니다.
  • onResume(): 액티비티가 화면에 완전히 나타나고 사용자와 상호작용할 준비가 되었을 때 호출됩니다.
  • onPause(): 다른 액티비티가 화면의 일부를 가리거나, 액티비티가 백그라운드로 들어가기 직전에 호출됩니다. 리소스를 해제하거나 데이터를 저장하는 등의 작업을 수행합니다.
  • onStop(): 액티비티가 사용자에게 더 이상 보이지 않을 때 호출됩니다.
  • onDestroy(): 액티비티가 완전히 종료될 때 호출됩니다. 시스템에 의해 강제 종료될 수도 있습니다.

이러한 콜백 메서드들을 적절히 활용하여 액티비티의 상태에 따라 필요한 작업을 수행함으로써 안정적인 앱을 만들 수 있습니다.

#액티비티 생명주기#콜백 메서드#상태 변화#onCreate#onResume

이 질문 단독 페이지 →

Q2 기초

안드로이드에서 Intent의 역할은 무엇이며, Explicit Intent와 Implicit Intent의 차이점을 구체적인 사용 사례와 함께 설명해주세요.

힌트 · 컴포넌트 간 통신 및 작업 요청을 위한 메시지 객체입니다. 명시적 인텐트는 특정 컴포넌트 지정, 암시적 인텐트는 시스템에 요청합니다.

Intent는 안드로이드에서 컴포넌트 간 통신을 담당하는 메시지 객체입니다. 주로 액티비티, 서비스, 브로드캐스트 리시버 등을 실행하거나 데이터를 전달할 때 사용됩니다.

전체 모범답안 펼치기

Intent는 안드로이드에서 컴포넌트 간 통신을 담당하는 메시지 객체입니다. 주로 액티비티, 서비스, 브로드캐스트 리시버 등을 실행하거나 데이터를 전달할 때 사용됩니다.

Explicit Intent와 Implicit Intent는 Intent를 사용하는 방식에 차이가 있습니다.

Explicit Intent는 실행할 컴포넌트의 클래스 이름을 명확하게 지정합니다. 예를 들어, "MainActivity에서 SecondActivity를 실행해줘" 와 같이 특정 액티비티를 직접 호출할 때 사용합니다.

Implicit Intent는 실행할 컴포넌트의 클래스 이름을 지정하지 않고, 수행할 작업(Action)과 데이터(Data)를 지정합니다. 예를 들어, "웹 페이지를 열어줘" 와 같이 시스템에 특정 작업을 요청할 때 사용합니다. 시스템은 해당 작업을 처리할 수 있는 앱을 찾아서 실행합니다. 웹 브라우저 앱이 여러 개 설치되어 있다면, 사용자에게 어떤 앱을 사용할지 선택하도록 할 수 있습니다.

#Intent#컴포넌트 간 통신#Explicit Intent#Implicit Intent#액티비티 호출

이 질문 단독 페이지 →

Q3 기초

안드로이드에서 UI를 구성할 때 사용되는 대표적인 레이아웃(LinearLayout, RelativeLayout, ConstraintLayout) 각각의 특징과 어떤 상황에서 주로 사용되는지 설명해주세요.

힌트 · LinearLayout은 선형 배치, RelativeLayout은 상대적 배치, ConstraintLayout은 제약 조건 기반 배치로 유연하고 복잡한 UI에 적합합니다.

안드로이드 UI 레이아웃에는 LinearLayout, RelativeLayout, ConstraintLayout이 대표적입니다.

전체 모범답안 펼치기

안드로이드 UI 레이아웃에는 LinearLayout, RelativeLayout, ConstraintLayout이 대표적입니다.

LinearLayout은 뷰들을 수직 또는 수평으로 선형 배치하는 가장 기본적인 레이아웃입니다. 간단한 UI를 빠르게 구성할 때 유용합니다.

RelativeLayout은 뷰들의 위치를 서로 상대적으로 지정합니다. 예를 들어, "A 뷰 아래에 B 뷰를 배치"하는 식으로요. 복잡한 UI를 만들 수 있지만, 레이아웃 계산 비용이 높을 수 있습니다.

ConstraintLayout은 뷰 간의 제약 조건을 설정하여 위치와 크기를 결정합니다. RelativeLayout의 단점을 보완하며, 유연하고 복잡한 UI를 효율적으로 구성할 수 있습니다. 특히 다양한 화면 크기에 대응하는 반응형 UI를 만들 때 강력합니다. 저는 복잡한 UI나 반응형 UI를 만들 때 ConstraintLayout을 선호합니다.

#LinearLayout#RelativeLayout#ConstraintLayout#제약#유연성

이 질문 단독 페이지 →

Q4 기초

안드로이드 개발에서 Context는 무엇을 의미하며, 어떤 상황에서 주로 사용되는지 최소 두 가지 이상의 예시를 들어 설명해주세요.

힌트 · 애플리케이션 환경 정보에 접근하고 시스템 서비스에 대한 접근을 제공합니다. 리소스 접근, 새 액티비티 시작 등에 사용됩니다.

Context는 안드로이드 애플리케이션의 현재 상태에 대한 인터페이스입니다. 쉽게 말해 앱의 환경 정보에 접근하고 시스템 서비스에 접근할 수 있도록 해주는 역할을 합니다.

전체 모범답안 펼치기

Context는 안드로이드 애플리케이션의 현재 상태에 대한 인터페이스입니다. 쉽게 말해 앱의 환경 정보에 접근하고 시스템 서비스에 접근할 수 있도록 해주는 역할을 합니다.

주로 사용하는 경우는 다음과 같습니다.

  1. 리소스 접근: Context를 통해 앱의 리소스 폴더 (drawable, layout 등)에 있는 이미지, 문자열, 레이아웃 파일 등에 접근할 수 있습니다. 예를 들어, context.getResources().getString(R.string.app_name)과 같이 문자열 리소스를 가져올 수 있습니다.

  2. 새 액티비티 시작: 새로운 액티비티를 시작할 때 Context가 필요합니다. context.startActivity(intent)와 같이 인텐트를 사용하여 새로운 화면을 띄울 수 있습니다.

Context는 Application Context와 Activity Context 등 다양한 종류가 있으며, 각각의 생명주기와 사용 목적이 다릅니다. 상황에 맞는 Context를 사용하는 것이 중요합니다.

#Context#Application Context#Activity Context#리소스 접근#시스템 서비스

이 질문 단독 페이지 →

Q5 기초

AndroidManifest.xml 파일의 주요 역할은 무엇이며, 이 파일에 반드시 포함되어야 하는 정보들은 어떤 것들이 있는지 설명해주세요.

힌트 · 애플리케이션의 핵심 정보, 컴포넌트 선언, 필요한 권한 등을 시스템에 알리는 파일입니다.

AndroidManifest.xml 파일은 안드로이드 앱의 '소개서' 같은 역할을 합니다. 앱의 기본적인 정보, 필요한 권한, 앱을 구성하는 주요 요소들을 안드로이드 시스템에 알려주는 역할을 하죠.

전체 모범답안 펼치기

AndroidManifest.xml 파일은 안드로이드 앱의 '소개서' 같은 역할을 합니다. 앱의 기본적인 정보, 필요한 권한, 앱을 구성하는 주요 요소들을 안드로이드 시스템에 알려주는 역할을 하죠.

반드시 포함되어야 하는 정보로는 먼저 앱의 이름, 아이콘, 패키지 이름 같은 기본적인 메타데이터가 있습니다. 그리고 앱을 구성하는 액티비티, 서비스, 브로드캐스트 리시버, 콘텐츠 프로바이더 같은 컴포넌트들을 선언해야 합니다.

또한, 앱이 필요로 하는 권한(permission)들을 명시해야 합니다. 예를 들어, 카메라를 사용하려면 카메라 권한을, 인터넷을 사용하려면 인터넷 권한을 선언해야 하죠. 마지막으로, 앱이 특정 인텐트에 응답할 수 있도록 인텐트 필터를 설정하는 것도 중요합니다. 앱이 지원하는 최소 SDK 버전과 타겟 SDK 버전 정보도 필수적으로 포함되어야 합니다.

#애플리케이션 메타데이터#컴포넌트 선언#퍼미션#인텐트 필터#SDK 버전

이 질문 단독 페이지 →

Q6 기초

안드로이드 UI 구성의 기본 요소인 View와 ViewGroup의 차이점을 설명하고, 각각의 예시를 들어주세요.

힌트 · View는 화면에 보이는 단일 UI 요소, ViewGroup은 다른 View나 ViewGroup을 포함하여 계층 구조를 형성하는 컨테이너입니다.

View와 ViewGroup은 안드로이드 UI를 구성하는 핵심 요소입니다. View는 화면에 보이는 기본적인 UI 요소, 예를 들어 버튼, 텍스트 뷰, 이미지 뷰 등을 의미합니다. 사용자와 직접 상호작용하는 역할을…

전체 모범답안 펼치기

View와 ViewGroup은 안드로이드 UI를 구성하는 핵심 요소입니다. View는 화면에 보이는 기본적인 UI 요소, 예를 들어 버튼, 텍스트 뷰, 이미지 뷰 등을 의미합니다. 사용자와 직접 상호작용하는 역할을 주로 담당합니다.

반면 ViewGroup은 다른 View나 또 다른 ViewGroup을 담는 컨테이너 역할을 합니다. 즉, View들을 그룹화하여 레이아웃을 구성하는 데 사용됩니다. 예를 들어 LinearLayout, RelativeLayout, ConstraintLayout 등이 ViewGroup에 해당하며, 이들은 View들을 어떻게 배치할지 결정하는 역할을 합니다. ViewGroup은 View를 상속받아 만들어졌기 때문에, ViewGroup 자체도 View의 일종이라고 볼 수 있습니다. 간단히 말해, View는 화면에 보이는 '무언가', ViewGroup은 그 '무언가'들을 담는 '틀'이라고 생각하면 이해하기 쉽습니다.

#View#ViewGroup#상속#레이아웃#컨테이너

이 질문 단독 페이지 →

Q7 기초

Kotlin의 Null Safety 기능은 무엇이며, 이를 위해 사용되는 '?' (nullable type)와 '!!' (non-null assertion operator)의 역할과 사용 시 주의점에 대해 설명해주세요.

힌트 · 널 포인터 예외 방지를 위한 기능입니다. '?'는 널이 될 수 있음을 명시하고, '!!'는 널이 아님을 강제하여 위험하게 사용될 수 있습니다.

Kotlin의 Null Safety는 널 포인터 예외(NullPointerException)를 방지하기 위한 기능입니다. Kotlin은 변수가 널 값을 가질 수 있는지 여부를 명확히 구분합니다.

전체 모범답안 펼치기

Kotlin의 Null Safety는 널 포인터 예외(NullPointerException)를 방지하기 위한 기능입니다. Kotlin은 변수가 널 값을 가질 수 있는지 여부를 명확히 구분합니다.

'?' (nullable type)는 변수가 널 값을 가질 수 있음을 나타냅니다. 예를 들어 String?은 String 타입이거나 null일 수 있다는 의미입니다. 이 변수를 사용할 때는 널 체크를 하거나 안전한 호출 연산자(?. )를 사용해야 합니다.

'!!' (non-null assertion operator)는 변수가 널이 아님을 강제로 단언하는 연산자입니다. 만약 '!!'를 사용했는데 실제 변수 값이 널이라면 NullPointerException이 발생합니다. 따라서 '!!'는 정말로 널이 될 가능성이 없다고 확신할 때만 신중하게 사용해야 합니다. 잘못 사용하면 Kotlin의 Null Safety 장점을 무효화하고 예외를 발생시킬 수 있습니다.

#NullPointerException#nullable type#non-null assertion#안전한 호출 연산자#컴파일 시점

이 질문 단독 페이지 →

읽기만으론 부족합니다. 직접 말해보세요

패스잇 앱에서 Android / Kotlin 질문에 직접 답하면 AI가 1:1로 답변을 코칭합니다.

Android / Kotlin 면접 질문 · 중급

Q8 중급

Activity의 onPause()와 onStop() 메서드는 어떤 차이가 있으며, 각각 어떤 상황에서 호출되고 어떤 작업을 수행하는 것이 적절한가요?

힌트 · onPause는 액티비티가 부분적으로 가려질 때, onStop은 완전히 가려질 때 호출됩니다. 리소스 해제 시점을 구분하여 설명하세요.

"onPause()와 onStop()은 액티비티 생명주기에서 액티비티의 가시성이 변화할 때 호출되는 메서드입니다.

전체 모범답안 펼치기

"onPause()와 onStop()은 액티비티 생명주기에서 액티비티의 가시성이 변화할 때 호출되는 메서드입니다.

onPause()는 액티비티가 부분적으로 가려질 때, 예를 들어 팝업 창이 뜨거나 다른 액티비티가 투명하게 겹쳐질 때 호출됩니다. 이 메서드에서는 CPU 자원을 많이 사용하는 작업은 피하고, 일시 정지해야 하는 작업 (예: 센서, 애니메이션)을 멈추는 것이 좋습니다. 짧은 시간 안에 액티비티가 다시 활성화될 가능성이 있기 때문입니다.

onStop()은 액티비티가 완전히 가려져 사용자에게 보이지 않게 될 때 호출됩니다. 이 메서드에서는 onPause()에서 처리하지 못한 리소스 해제 작업을 수행할 수 있습니다. 예를 들어, 네트워크 연결을 끊거나, 데이터를 저장하는 등의 작업을 할 수 있습니다. 시스템은 메모리가 부족할 경우 onStop() 상태의 액티비티를 종료시킬 수 있습니다."

#onPause#onStop#가시성#생명주기#리소스 해제

이 질문 단독 페이지 →

Q9 중급

Fragment의 onCreateView()와 onViewCreated() 메서드의 호출 시점과 역할의 차이점을 설명하고, 각각 어떤 종류의 작업을 수행하는 것이 권장되는지 예시와 함께 설명해 주세요.

힌트 · onCreateView는 뷰 계층을 생성하고 반환하며, onViewCreated는 뷰가 생성된 후 초기화 작업을 수행합니다. 뷰 바인딩 및 데이터 바인딩 적용 시점을 고려하세요.

Fragment의 onCreateView()와 onViewCreated()는 Fragment의 생명주기에서 뷰와 관련된 중요한 역할을 담당합니다.

전체 모범답안 펼치기

Fragment의 onCreateView()와 onViewCreated()는 Fragment의 생명주기에서 뷰와 관련된 중요한 역할을 담당합니다.

onCreateView()는 Fragment의 뷰 계층을 생성하고 반환하는 역할을 합니다. 이 메서드 안에서 레이아웃 XML 파일을 inflate하여 뷰를 생성하고, 생성된 뷰를 Fragment에 연결합니다. 예를 들어, LayoutInflater.inflate(R.layout.my_fragment, container, false)와 같이 레이아웃을 inflate하는 코드가 주로 이 메서드 안에 위치합니다.

onViewCreated()는 onCreateView()에서 뷰가 생성된 후에 호출됩니다. 즉, 뷰가 Fragment에 연결되고, 뷰 계층이 완전히 생성된 시점입니다. 따라서 findViewById()를 사용하여 뷰의 요소들을 찾고, 초기화 작업을 수행하기에 적합합니다. 예를 들어, 텍스트뷰에 초기 텍스트를 설정하거나, 리사이클러뷰 어댑터를 설정하는 등의 작업을 onViewCreated()에서 수행합니다. 또한, 뷰 바인딩이나 데이터 바인딩을 사용하는 경우, 이 시점에서 바인딩 객체를 초기화하고 데이터를 연결하는 것이 좋습니다.

정리하자면, onCreateView()는 뷰를 "만드는" 역할, onViewCreated()는 만들어진 뷰를 "초기화하고 사용하는" 역할이라고 생각하면 이해하기 쉽습니다.

#뷰 생성#레이아웃 인플레이션#findViewById#뷰 초기화#데이터 바인딩

이 질문 단독 페이지 →

Q10 중급

Android 아키텍처 컴포넌트 중 ViewModel의 역할과 장점은 무엇이며, Activity 또는 Fragment의 생명주기와 어떻게 독립적으로 데이터를 유지할 수 있는지 설명해주세요.

힌트 · ViewModel은 구성 변경(예: 화면 회전) 시에도 데이터를 유지하며, UI 컨트롤러와 데이터를 분리하여 생명주기 종속성 문제를 해결합니다.

ViewModel은 Android 아키텍처 컴포넌트 중 하나로, UI에 필요한 데이터를 저장하고 관리하는 역할을 합니다. Activity나 Fragment와 같은 UI 컨트롤러의 생명주기와 독립적으로 동작하여, 화면…

전체 모범답안 펼치기

ViewModel은 Android 아키텍처 컴포넌트 중 하나로, UI에 필요한 데이터를 저장하고 관리하는 역할을 합니다. Activity나 Fragment와 같은 UI 컨트롤러의 생명주기와 독립적으로 동작하여, 화면 회전과 같은 구성 변경 시에도 데이터를 유지할 수 있다는 장점이 있습니다.

ViewModel을 사용하면 UI 컨트롤러는 데이터 표시와 사용자 인터랙션 처리라는 본연의 역할에 집중할 수 있게 됩니다. 데이터 로딩이나 복잡한 비즈니스 로직은 ViewModel에서 처리하므로 UI 코드가 간결해지고 테스트하기 쉬워집니다.

Activity나 Fragment가 소멸되고 재 생성되더라도 ViewModel은 유지되므로, UI 데이터가 초기화되지 않습니다. 이는 ViewModelProvider를 통해 ViewModel을 생성하고 관리함으로써 가능합니다.

#UI 데이터#생명주기#데이터 유지#Configuration Change#UI 로직 분리

이 질문 단독 페이지 →

Q11 중급

Kotlin Flow 기반의 StateFlow와 Android 아키텍처 컴포넌트의 LiveData는 각각 어떤 특징을 가지고 있으며, UI 상태 관리에 있어 어떤 상황에서 어떤 것을 사용하는 것이 더 효과적인지 비교하여 설명해주세요.

힌트 · LiveData는 lifecycle-aware하며 단일 값에 최적화되어 있고, StateFlow는 Flow의 강력한 연산자를 활용하며 cold/hot stream 특성을 가집니다. 사용 사례와 리소스 소모 측면에서 비교하세요.

StateFlow와 LiveData는 모두 UI 상태 관리에 사용되지만 몇 가지 중요한 차이점이 있습니다.

전체 모범답안 펼치기

StateFlow와 LiveData는 모두 UI 상태 관리에 사용되지만 몇 가지 중요한 차이점이 있습니다.

LiveData는 Android 아키텍처 컴포넌트의 일부로, lifecycle-aware하다는 장점이 있습니다. 즉, Activity나 Fragment의 lifecycle 상태를 자동으로 감지하여 불필요한 업데이트를 방지합니다. 또한 단일 값 홀더로서 간단한 데이터 스트림에 최적화되어 있습니다.

반면 StateFlow는 Kotlin Flow 기반으로, 더 강력한 연산자를 활용할 수 있습니다. Hot stream이기 때문에 구독 시점에 관계없이 항상 최신 값을 방출하며, 여러 개의 값을 지속적으로 방출하는 복잡한 상태 관리에 유용합니다.

어떤 것을 선택할지는 상황에 따라 다릅니다. 간단한 UI 상태 업데이트, lifecycle 관리가 중요한 경우에는 LiveData가 적합합니다. 복잡한 상태 변화를 처리하고 Flow의 다양한 연산자를 활용하고 싶다면 StateFlow가 더 나은 선택일 수 있습니다. StateFlow는 LiveData에 비해 리소스 소모가 더 클 수 있다는 점도 고려해야 합니다.

#StateFlow#LiveData#Cold Stream#Hot Stream#상태 홀더

이 질문 단독 페이지 →

Q12 중급

코틀린 코루틴에서 Dispatchers.Main, Dispatchers.IO, Dispatchers.Default의 역할과 각각 어떤 종류의 작업에 적합한지 구체적인 사용 사례와 함께 설명해주세요.

힌트 · Main은 UI 작업, IO는 네트워크/디스크 I/O, Default는 CPU-intensive 작업에 사용됩니다. 적절한 Dispatcher 선택이 성능에 미치는 영향을 설명하세요.

코틀린 코루틴에서 Dispatchers는 코루틴이 실행될 스레드를 지정하는 역할을 합니다.

전체 모범답안 펼치기

코틀린 코루틴에서 Dispatchers는 코루틴이 실행될 스레드를 지정하는 역할을 합니다.

  • Dispatchers.Main은 UI 스레드에서 코루틴을 실행합니다. UI 업데이트와 같이 UI와 관련된 작업에 사용해야 합니다. 예를 들어, LiveData 값을 변경하거나, 뷰의 속성을 변경하는 경우 Main Dispatcher를 사용합니다.

  • Dispatchers.IO는 네트워크 작업이나 디스크 I/O와 같은 블로킹 I/O 작업에 최적화되어 있습니다. 데이터베이스 쿼리, 파일 읽기/쓰기, 네트워크 요청 등에 사용하면 됩니다.

  • Dispatchers.Default는 CPU를 많이 사용하는 작업에 적합합니다. 이미지 처리, 복잡한 계산 등 시간이 오래 걸리는 작업에 사용하면 UI 스레드를 막지 않고 백그라운드에서 처리할 수 있습니다.

적절한 Dispatcher를 선택하는 것은 앱 성능에 매우 중요합니다. UI 스레드에서 CPU를 많이 사용하는 작업을 실행하면 앱이 멈추거나 응답하지 않을 수 있습니다. 반대로, I/O 작업을 Default Dispatcher에서 실행하면 스레드 풀이 효율적으로 사용되지 않아 성능 저하가 발생할 수 있습니다.

#Dispatchers.Main#Dispatchers.IO#Dispatchers.Default#UI 스레드#블로킹 I/O

이 질문 단독 페이지 →

Q13 중급

Android에서 Hilt(또는 Dagger Hilt)를 사용하여 의존성 주입(DI)을 구현할 때, @Inject, @Module, @Provides 어노테이션의 역할과 사용 방법에 대해 설명하고, 빌드 타임에 어떻게 의존성 그래프가 생성되는지 간략하게 설명해 주세요.

힌트 · @Inject는 생성자/필드 주입, @Module과 @Provides는 외부 라이브러리나 인터페이스에 대한 의존성을 제공합니다. 컴파일 시 코드 생성 원리를 간략히 언급하세요.

Hilt에서 의존성 주입을 할 때, @Inject, @Module, @Provides 어노테이션은 중요한 역할을 합니다.

전체 모범답안 펼치기

Hilt에서 의존성 주입을 할 때, @Inject, @Module, @Provides 어노테이션은 중요한 역할을 합니다.

@Inject는 Hilt에게 해당 클래스의 인스턴스를 주입해 달라고 요청하는 어노테이션입니다. 주로 생성자 주입이나 필드 주입에 사용됩니다. 예를 들어, 클래스 생성자에 @Inject를 붙이면 Hilt가 필요한 의존성을 자동으로 주입해줍니다.

@Module은 의존성을 제공하는 방법을 정의하는 클래스에 붙이는 어노테이션입니다. 주로 외부 라이브러리나 인터페이스처럼 직접 생성자를 수정할 수 없는 경우에 사용합니다.

@Provides는 @Module 안에서 특정 타입의 인스턴스를 어떻게 생성하고 제공할지 정의하는 메서드에 붙이는 어노테이션입니다.

Hilt는 컴파일 타임에 이러한 어노테이션들을 분석하여 의존성 그래프를 생성합니다. 이 그래프는 애플리케이션 내의 모든 의존 관계를 나타내며, Hilt는 이 그래프를 기반으로 필요한 의존성을 자동으로 주입해줍니다. 컴파일 시점에 코드를 생성하여 런타임 성능 저하를 최소화하는 것이 특징입니다.

#@Inject#@Module#@Provides#의존성 그래프#컴파일 타임

이 질문 단독 페이지 →

Q14 중급

Android Jetpack Navigation Component를 사용하여 앱 내 화면 간 이동을 구현할 때의 장점은 무엇이며, NavController, NavGraph, NavHostFragment가 각각 어떤 역할을 하는지 설명해주세요.

힌트 · Navigation Component는 화면 전환을 중앙에서 관리하며, Safe Args와 같은 기능을 통해 타입 안정성을 제공합니다. 각 구성 요소의 역할 분담을 설명하세요.

Android Jetpack Navigation Component를 사용하면 앱 내 화면 이동을 훨씬 효율적으로 관리할 수 있습니다. 가장 큰 장점은 단일 액티비티 아키텍처를 쉽게 구현할 수 있다는 점입니다. 화면…

전체 모범답안 펼치기

Android Jetpack Navigation Component를 사용하면 앱 내 화면 이동을 훨씬 효율적으로 관리할 수 있습니다. 가장 큰 장점은 단일 액티비티 아키텍처를 쉽게 구현할 수 있다는 점입니다. 화면 전환 로직을 중앙 집중적으로 관리하여 코드 중복을 줄이고 유지보수성을 높여줍니다. 또한, Safe Args를 사용하면 화면 간 데이터 전달 시 타입 안정성을 확보할 수 있어 런타임 오류를 예방할 수 있습니다.

각 구성 요소의 역할은 다음과 같습니다. NavController는 화면 이동을 수행하는 핵심 컨트롤러입니다. NavGraph는 앱 내 모든 탐색 경로를 정의하는 XML 파일로, 화면 간의 관계를 시각적으로 보여줍니다. NavHostFragment는 NavGraph를 호스팅하고 화면 전환을 처리하는 컨테이너 역할을 합니다. NavController를 통해 NavHostFragment 내에서 화면을 전환하게 됩니다.

#단일 액티비티 아키텍처#UI 컨트롤러 관리#탐색 그래프#NavController#NavHostFragment

이 질문 단독 페이지 →

Android / Kotlin 면접 질문 · 심화

Q15 심화

Jetpack Compose에서 Recomposition의 동작 원리를 설명하고, 불필요한 Recomposition을 최소화하여 Compose UI 성능을 최적화하는 구체적인 전략들을 제시해 보세요.

힌트 · `remember` 사용, `stable` 타입 정의, `key` 활용, 람다 캡처링 방지 등을 고려해야 합니다. Compose 컴파일러 리포트를 분석하는 것도 중요합니다.

Jetpack Compose에서 Recomposition은 상태(State)가 변경되었을 때 UI를 업데이트하는 과정입니다. Compose는 변경된 부분만 다시 그리는 방식으로 동작하여 효율성을 높입니다.

전체 모범답안 펼치기

Jetpack Compose에서 Recomposition은 상태(State)가 변경되었을 때 UI를 업데이트하는 과정입니다. Compose는 변경된 부분만 다시 그리는 방식으로 동작하여 효율성을 높입니다.

Recomposition 최적화를 위해 몇 가지 전략을 사용할 수 있습니다. 첫째, remember를 사용하여 불필요한 객체 생성을 막고, 상태를 유지합니다. 둘째, stable 타입으로 정의된 데이터 클래스를 사용하여 Compose가 변경 여부를 더 정확하게 판단하도록 돕습니다. 셋째, key를 사용하여 특정 컴포저블이 업데이트되어야 하는지 명시적으로 지정할 수 있습니다. 넷째, 람다 캡처링을 최소화하여 불필요한 Recomposition을 방지합니다. 예를 들어, 람다 내에서 외부 상태를 직접 사용하는 대신, 필요한 값만 인자로 전달하는 것이 좋습니다.

마지막으로, Compose 컴파일러 리포트를 분석하여 어떤 컴포저블이 Recomposition을 유발하는지 파악하고, 개선점을 찾는 것이 중요합니다. derivedStateOf를 사용하여 특정 상태에 의존하는 값을 계산하고, 해당 값의 변경에 따라서만 Recomposition이 일어나도록 할 수도 있습니다. 이러한 전략들을 통해 Compose UI의 성능을 효과적으로 최적화할 수 있습니다.

#상태(State)#불변성(Immutability)#스키핑(Skipping)#remember#derivedStateOf

이 질문 단독 페이지 →

Q16 심화

대규모 안드로이드 프로젝트에서 멀티 모듈 아키텍처를 도입할 때의 장점과 단점을 설명하고, 모듈 간의 의존성 관리 및 순환 의존성 문제를 해결하는 방안에 대해 논의해 보세요.

힌트 · 빌드 속도 향상, 책임 분리, 코드 재사용성 등의 장점과 복잡성 증가, 설정 오버헤드 등의 단점을 설명합니다. DI와 인터페이스 기반의 분리를 통해 순환 의존성을 방지할 수 있습니다.

대규모 안드로이드 프로젝트에서 멀티 모듈 아키텍처를 도입하면 여러 장점이 있습니다. 빌드 속도가 빨라지고, 각 모듈별로 책임이 분리되어 유지보수가 용이해집니다. 또한, 공통 기능을 모듈로 분리하여 코드 재사용성을 높…

전체 모범답안 펼치기

대규모 안드로이드 프로젝트에서 멀티 모듈 아키텍처를 도입하면 여러 장점이 있습니다. 빌드 속도가 빨라지고, 각 모듈별로 책임이 분리되어 유지보수가 용이해집니다. 또한, 공통 기능을 모듈로 분리하여 코드 재사용성을 높일 수 있습니다.

하지만 단점도 존재합니다. 프로젝트 구조가 복잡해지고, 모듈 간의 설정 오버헤드가 증가할 수 있습니다.

모듈 간 의존성 관리는 Gradle을 통해 이루어지며, API와 Implementation을 적절히 사용하여 의존성을 제어합니다. 순환 의존성 문제는 주로 인터페이스 기반으로 모듈을 분리하고, DI(Dependency Injection) 라이브러리를 활용하여 해결합니다. 예를 들어, A 모듈이 B 모듈에 의존하고, B 모듈이 A 모듈에 의존하는 경우, A 모듈은 B 모듈의 인터페이스에만 의존하도록 설계하여 순환 참조를 방지할 수 있습니다.

#모듈화#빌드 시간#의존성 주입#인터페이스#순환 참조

이 질문 단독 페이지 →

Q17 심화

Android 8.0 (Oreo) 이후 강화된 백그라운드 실행 제한 사항들을 설명하고, 이러한 제약 하에서 안정적이고 효율적인 백그라운드 작업을 구현하기 위한 Jetpack WorkManager 활용 전략을 제시해 보세요.

힌트 · Implicit Broadcast 제한, 백그라운드 서비스 제한 등을 언급하고, WorkManager의 제약 조건, 지연 실행, 네트워크 조건 등을 활용하는 방법을 설명합니다.

Android 8.0 (Oreo)부터 백그라운드 실행에 대한 제약이 크게 강화되었습니다. 암시적 브로드캐스트 수신이 제한되고, 백그라운드 서비스 실행도 어려워졌죠. Doze 모드나 앱 대기 버킷 같은 배터리 관리 기…

전체 모범답안 펼치기

Android 8.0 (Oreo)부터 백그라운드 실행에 대한 제약이 크게 강화되었습니다. 암시적 브로드캐스트 수신이 제한되고, 백그라운드 서비스 실행도 어려워졌죠. Doze 모드나 앱 대기 버킷 같은 배터리 관리 기능도 백그라운드 작업에 영향을 미칩니다.

이러한 제약 하에서 안정적인 백그라운드 작업을 구현하기 위해 Jetpack WorkManager를 적극적으로 활용할 수 있습니다. WorkManager는 JobScheduler를 기반으로 동작하며, 제약 조건(Constraints)을 설정하여 특정 조건(네트워크 연결, 충전 상태 등)이 만족될 때 작업을 실행하도록 할 수 있습니다.

예를 들어, 네트워크 연결이 필요하고, 기기가 충전 중일 때만 데이터를 동기화하는 작업을 WorkManager로 예약할 수 있습니다. 또한, 작업이 실패했을 경우 재시도 정책을 설정하여 안정성을 높일 수 있습니다. WorkManager는 OS 버전에 따라 최적의 방식으로 작업을 처리해주므로 개발자는 백그라운드 작업 관리에 더욱 집중할 수 있습니다.

#백그라운드 실행 제한#Doze 모드#App Standby 버킷#JobScheduler#WorkManager

이 질문 단독 페이지 →

Q18 심화

코루틴의 Dispatchers 종류와 각 Dispatcher의 역할에 대해 설명하고, CoroutineScope를 올바르게 사용하여 메모리 누수를 방지하고 코루틴 생명주기를 관리하는 방법에 대해 구체적인 예시와 함께 설명해 주세요.

힌트 · `Main`, `IO`, `Default` Dispatcher의 용도를 설명하고, `viewModelScope`, `lifecycleScope` 등의 사용과 커스텀 스코프 생성 시 주의점을 언급합니다.

코루틴 Dispatchers는 코루틴이 실행될 스레드를 결정합니다. Dispatchers.Main은 UI 스레드에서 동작하며 UI 업데이트에 사용됩니다. Dispatchers.IO는 네트워크나 디스크 I/O에 최적화…

전체 모범답안 펼치기

코루틴 Dispatchers는 코루틴이 실행될 스레드를 결정합니다. Dispatchers.Main은 UI 스레드에서 동작하며 UI 업데이트에 사용됩니다. Dispatchers.IO는 네트워크나 디스크 I/O에 최적화된 스레드 풀을 사용하고, Dispatchers.Default는 CPU 집약적인 작업에 적합합니다.

CoroutineScope는 코루틴의 생명주기를 관리합니다. viewModelScope나 lifecycleScope를 사용하면 액티비티나 뷰모델의 생명주기에 맞춰 코루틴이 자동으로 취소되어 메모리 누수를 방지할 수 있습니다.

예를 들어, 뷰모델에서 데이터를 가져오는 코루틴을 실행할 때 viewModelScope.launch { fetchData() }처럼 사용하면 뷰모델이 소멸될 때 코루틴도 함께 취소됩니다. 커스텀 스코프를 만들 때는 Job을 사용하여 코루틴의 생명주기를 명확하게 관리하고, 더 이상 필요하지 않을 때 cancel() 메서드를 호출해야 합니다.

#Dispatchers#CoroutineScope#Job#lifecycle#메모리 누수

이 질문 단독 페이지 →

Q19 심화

Dagger 또는 Hilt에서 컴포넌트(Component)의 계층 구조가 필요한 이유와 이를 어떻게 설계하고 사용하는지 설명하고, 특정 스코프(예: @Singleton, @ActivityScoped)가 컴포넌트 계층 구조와 어떤 관계를 가지는지 설명해 보세요.

힌트 · 리소스 공유 및 생명주기 관리를 위한 계층 구조의 필요성을 설명하고, 각 스코프가 바인딩되는 컴포넌트의 생명주기와 일치함을 언급합니다.

Dagger나 Hilt에서 컴포넌트 계층 구조가 필요한 이유는 크게 두 가지입니다. 첫째, 의존성 격리를 통해 특정 컴포넌트에서만 필요한 의존성을 분리하여 관리하고, 둘째, 메모리 누수를 방지하고 생명주기를 효과적으…

전체 모범답안 펼치기

Dagger나 Hilt에서 컴포넌트 계층 구조가 필요한 이유는 크게 두 가지입니다. 첫째, 의존성 격리를 통해 특정 컴포넌트에서만 필요한 의존성을 분리하여 관리하고, 둘째, 메모리 누수를 방지하고 생명주기를 효과적으로 관리하기 위해서입니다.

예를 들어, Activity 컴포넌트는 Application 컴포넌트의 서브컴포넌트가 될 수 있습니다. 이렇게 하면 Activity에 필요한 의존성은 Activity 컴포넌트 내에서만 생성되고 관리되며, Activity가 종료될 때 함께 소멸됩니다.

스코프는 컴포넌트의 생명주기와 밀접하게 관련됩니다. @Singleton 스코프는 Application 컴포넌트와 같이 애플리케이션 생명주기 동안 유지되는 의존성에 사용되고, @ActivityScoped는 Activity 컴포넌트와 같이 Activity 생명주기 동안 유지되는 의존성에 사용됩니다. 스코프를 통해 의존성이 필요한 시점에 생성되고 불필요해지면 소멸되도록 관리할 수 있습니다. 컴포넌트 계층 구조와 스코프를 적절히 사용하면 의존성 관리를 효율적으로 할 수 있습니다.

#의존성 격리#스코프 관리#컴포넌트 재사용#서브컴포넌트#의존성 그래프

이 질문 단독 페이지 →

Q20 심화

안드로이드 앱의 콜드 스타트(Cold Start) 프로세스를 설명하고, 콜드 스타임(Cold Start Time)을 효과적으로 줄이기 위한 구체적인 최적화 방안들을 제시해 보세요.

힌트 · Application 클래스 최적화, 불필요한 라이브러리 초기화 지연, 스플래시 화면 최적화, 프로파일링 도구 활용 등을 설명합니다.

안드로이드 앱 콜드 스타트는 앱이 시스템에 의해 완전히 종료된 후 처음 실행될 때 발생합니다. 이 때는 시스템이 앱 프로세스를 생성하고, Application 객체를 초기화하며, 첫 번째 Activity를 화면에 표…

전체 모범답안 펼치기

안드로이드 앱 콜드 스타트는 앱이 시스템에 의해 완전히 종료된 후 처음 실행될 때 발생합니다. 이 때는 시스템이 앱 프로세스를 생성하고, Application 객체를 초기화하며, 첫 번째 Activity를 화면에 표시하는 모든 과정을 거치기 때문에 시간이 오래 걸릴 수 있습니다.

콜드 스타트 시간을 줄이기 위해 몇 가지 최적화 방안을 적용할 수 있습니다. 먼저, Application 클래스에서 불필요한 초기화를 최소화해야 합니다. 무거운 작업이나 네트워크 요청은 앱이 실제로 필요할 때까지 지연시키는 Lazy Initialization을 활용하는 것이 좋습니다. 예를 들어, 특정 라이브러리가 특정 화면에서만 사용된다면, 해당 화면이 로드될 때 초기화하도록 구현할 수 있습니다.

스플래시 화면을 사용하는 경우, 화면 표시 시간을 최소화하고, 실제 콘텐츠 로딩은 백그라운드 스레드에서 처리해야 합니다. 또한, 프로파일링 도구를 사용하여 병목 지점을 파악하고, 해당 부분을 집중적으로 최적화하는 것이 중요합니다. LayoutInflater의 사용을 최적화하거나, ContentProvider 초기화를 지연시키는 방법도 고려할 수 있습니다.

#Application#Activity#LayoutInflater#ContentProvider#Lazy Initialization

이 질문 단독 페이지 →

Q21 심화

복잡한 Custom View를 설계할 때, onMeasure, onLayout, onDraw 메서드 내에서 발생할 수 있는 성능 병목 현상과 이를 해결하기 위한 전략들을 설명하고, 복잡한 레이아웃을 효율적으로 처리하기 위한 접근 방식을 제시해 보세요.

힌트 · 불필요한 객체 생성 최소화, 캐싱, 하드웨어 가속 활용, `invalidate()`/`requestLayout()` 호출 최소화, ViewStub, Merge 태그 등을 고려합니다.

복잡한 Custom View 성능 병목은 주로 onMeasure, onLayout, onDraw에서 발생합니다. onMeasure에서는 MeasureSpec을 잘못 다루거나, 불필요한 크기 계산 반복이 문제가 될 수…

전체 모범답안 펼치기

복잡한 Custom View 성능 병목은 주로 onMeasure, onLayout, onDraw에서 발생합니다. onMeasure에서는 MeasureSpec을 잘못 다루거나, 불필요한 크기 계산 반복이 문제가 될 수 있습니다. onLayout에서는 잦은 레이아웃 변경, onDraw에서는 과도한 객체 생성이나 복잡한 연산이 성능 저하를 일으키죠.

해결 전략으로는, 먼저 객체 생성을 최소화하고, 계산 결과를 캐싱하여 재사용합니다. 하드웨어 가속을 활성화하고, invalidate()나 requestLayout() 호출을 최대한 줄여야 합니다. 뷰의 복잡성을 줄이기 위해 ViewStub이나 Merge 태그를 활용하는 것도 좋은 방법입니다.

복잡한 레이아웃을 효율적으로 처리하려면, ConstraintLayout을 사용하여 레이아웃 계산 비용을 줄이거나, Custom View 내에서 필요한 부분만 그리도록 최적화하는 것이 중요합니다. 필요하다면 View.LAYER_TYPE_HARDWARE를 사용하여 렌더링 성능을 향상시킬 수도 있습니다.

#invalidate()#requestLayout()#캐싱#View.LAYER_TYPE_HARDWARE#MeasureSpec

이 질문 단독 페이지 →

함께 보면 좋은 모바일 개발 면접 질문

모바일 개발 면접 질문 전체 보기 → 전체 카테고리

보유한 Android / Kotlin 질문은 이게 전부가 아닙니다

패스잇 앱에는 직무별 면접 질문 수천 개와 모범답안이 담겨 있습니다. AI 모의면접으로 직접 답하고, 약점을 분석받아 보세요.