안드로이드 기술 면접 책 북 스터디를 하면서
보다 간결하게 실제 면접하는 것처럼 글을 정리해보려 한다.
중요하다고 생각된 질문만 정리했다.
Q41) RecyclerView는 내부적으로 어떻게 동작하나요?
RecyclerVIew는 새로운 아이템 뷰를 반복적으로 인플레이션 하는 대신 재활용하여
대규모 데이터 셋을 효율적으로 표시하도록 설계된 유용하고 유연한 안드로이드 컴포넌트입니다.
ViewHolder 패턴으로 알려진 뷰관리를 위한 객체 풀과 유사한 매커니즘을 사용하여 이러한 효율성을 달성합니다.
RecyclerView 내부 매커니즘의 핵심 개념
- 뷰 재활용(Recycling Views)
RecyclerView는 데이터 셋의 모든 항목에 대해 새 뷰를 생성하는 대신 기존 뷰를 재사용합니다.
뷰가 보이는 영역 밖으로 스크롤되면 소멸되는 대신 뷰 홀더에 추가됩니다.
새 항목이 뷰에 들어오면 RecyclerView는 가능한 이 풀에서 기존 뷰를 검색하여 인플레이션 오버헤드를 피합니다. - ViewHolder 패턴
RecyclerView는 항목 레이아웃 내 뷰에 대한 참조를 저장하기 위해 ViewHolder를 사용합니다.
이는 바인딩 중 반복적인 findViewById() 호출을 방지하여 레이아웃 순회 및 뷰 조회를 줄여 성능을 향상시킵니다. - Adapter의 역할
RecyclerView.Adapter는 데이터 소스와 RecyclerView를 연결하는 다리 역할을 합니다.
어댑터의 onBindViewHolder() 메서드는 뷰가 재사용될 때 데이터를 뷰에 바인딩하여 보이는 항목만 업데이트하도록 보장합니다. - RecycledViewPool
RecycledViewPool은 사용되지 않는 뷰가 저장되는 객체 풀 역할을 합니다.
이를 통해서 RecyclerView는 유사한 뷰 유형을 가진 여러 목록 또는 섹션에서 뷰를 재사용하여 메모리 사용량을 더욱 최적화할 수 있습니다.
재활용 매커니즘
- 스크롤 및 항목 가시성
스크롤하면 뷰 밖으로 나가는 항목은 RecyclerView에서 분리되지만 소멸되지 않습니다.
대신 RecycledViewPool에 추가됩니다. - 재활용된 뷰에 데이터 리바인딩
새 항목이 뷰에 들어오면 RecycledView는 먼저 RecycledViewPool에서 필요한 유형의 사용 가능한 뷰를 지원합니다.
일치하면 onBindViewHolder()를 사용하여 새 데이터로 리바인딩하여 뷰를 재사용합니다. - 사용 가능한 뷰가 없는 경우
풀에 적합한 뷰가 없는 경우 RecyclerView는 onCreateViewHolder()를 사용하여 새 뷰를 인플레이션합니다. - 효율적인 메모리 사용
뷰를 재활용함으로써 RecyclerView는 메모리 할당 및 가비지 컬렉션을 최소화하여 대규모 데이터 셋이나
빈번한 스크롤이 포함된 시나리오에서 발생할 수 있는 성능 문제를 줄입니다.
RecyclerView의 객체 풀 접근 방식의 장점
- 향상된 성능
새 레이아웃 인플레이션 오버헤드가 줄어들어 더 부드러운 스크롤과 더 나은 성능을 제공 - 효율적인 메모리 관리
객체 풀은 뷰를 재활용하여 메모리 할당을 최소화하고 빈번한 가비지 컬렉션을 방지 - 커스텀
RecycledViewPool은 각 유형에 대한 최대 뷰 수를 관리하도록
커스텀할 수 있어 개발자가 특정 사용 사례에 대한 동작을 최적화할 수 있습니다.
Q45) 안드로이드의 Bitmap이란 무엇이며, 큰 Bitmap을 효율적으로 처리하는 방법은 무엇인가요?
Bitmap은 메모리 내에 픽셀 데이터를 보관하는 이미지 표현입니다.
리소스/파일/네트워크 등에서 가져온 이미지를 화면에 렌더링할 때 사용하며
고해상도 이미지의 경우 메모리 사용량이 매우 커 OutOfMemoryError가 쉽게 발생할 수 있습니다.
큰 Bitmap의 문제
- 과도한 메모리 소비 : 필요 이상 해상도의 이미지를 전부 로드하면 byteCount가 커짐
- 성능 저하 : 디코딩 GC 부담으로 프레임 드랍
- 크래시 위험 : 메모리 압박으로 OOM 발생 가능
메모리를 할당하지 않고 Bitmap 크기 읽기 (inJustDecodeBounds)
이미지를 전부 로드하기 전에 메타데이터(가로, 세로, mime)만 확인해 필요성/목표 크기를 판단합니다.
val options = BitmapFactory.Options().apply {
inJustDecodeBounds = true
}
BitmapFactory.decodeResource(resources, R.drawable.my_image, options)
val imageWidth = options.outWidth
val imageHeight = options.outHeight
val imageType = options.outMimeType
inSampleSize로 축소 디코딩
목표 크기(reqWidth, reqHeight)에 맞춰 2의 배수로 서브샘플링하여 메모리를 절감합니다.
fun calculateInSampleSize(
options: BitmapFactory.Options,
reqWidth: Int,
reqHeight: Int
): Int {
val (height, width) = options.run { outHeight to outWidth }
var inSampleSize = 1
if (height > reqHeight || width > reqWidth) {
var halfHeight = height / 2
var halfWidth = width / 2
while ((halfHeight / inSampleSize) >= reqHeight &&
(halfWidth / inSampleSize) >= reqWidth) {
inSampleSize *= 2
}
}
return inSampleSize
}
서브샘플링을 사용한 전체 디코딩
calculateInSampleSize를 사용하여 두 단계로 비트맵을 디코딩할 수 있습니다.
- 경계만 디코딩합니다.
- 계산된 inSampleSize를 설정하고 축소된 비트맵을 디코딩합니다.
fun decodeSampledBitmapFromResource(
res: Resources,
resId: Int,
reqWidth: Int,
reqHeight: Int
): Bitmap? {
return BitmapFactory.Options().run {
inJustDecodeBounds = true
BitmapFactory.decodeResource(res, resId, this)
// inSampleSize 계산
inSampleSize = calculateInSampleSize(this, reqWidth, reqHeight)
// inSampleSize를 설정하고 비트맵 디코딩
inJustDecodeBounds = false
BitmapFactory.decodeResource(res, resId, this)
}
val bitmap = decodeSampledBitmapFromResource(
resources,
R.drawable.my_image,
reqWidth = 100,
reqHeight = 100
)
imageView.setImageBitmap(bitmap)
요약
- Bitmap은 픽셀 단위 메모리로 메모리 사용량이 크므로 목적 크기에 맞춘 샘플링 디코딩이 핵심
- inJustDecodeBounds로 메타데이터만 선 확인 -> inSampleSize로 축소 디코딩 -> 필쇼이 inPreferredConfig로 추가 절감
Q48) 웹 페이지를 어떻게 렌더링하나요?
WebView는 앱 내에서 웹 콘텐츠를 렌더링하고 상호작용할 수 있게 하는 컴포넌트입니다.
최신 기능/호환성 확보를 위해 AndroidX WebKit 사용을 권장합니다.
<!-- activity_main.xml -->
<WebView
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
val webView: WebView = findViewById(R.id.webView)
webView.loadUrl("https://www.example.com")
JavaScript 실행/브릿지
// 실행 결과 콜백 (API 19+)
webView.evaluateJavascript("document.body.style.background='red'\u003B") { result ->
Log.d("WebView", "JS result: $result")
}
// JS ↔ Android 브릿지
class WebAppInterface(private val context: Context) {
@JavascriptInterface fun showToast(message: String) {
Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
}
}
webView.settings.javaScriptEnabled = true
webView.addJavascriptInterface(WebAppInterface(this), "Android")
보안 고려사항
- 불필요한 JavaScript 비활성화
- 파일 접근 허용 옵션 신중히 사용
- URL/입력 검증으로 XSS/스푸핑 방지
- @JavaScriptInterface로 노출된 메서드 최소화 검증
요약
- webView는 앱 내 미니 브라우저로, 로드/네비게이션/JS/다운로드를 커스텀 가능
- WebViewClient로 인앱 네비게이션 유지, evaluateJavascript와 브릿지로 상호작용
- 보안 성능 영향 고려, 필요시 AndroidX webKit로 최신 기능 활용
Q49) AppCompat 라이브러리란 무엇인가요?
AppCompat 라이브러리는 개발자가 하위 버전의 안드로이드와의 호환성을 유지하는 데
도움이 되도록 설계된 Android Jetpack 제품군의 일부입니다.
하위 안드로이드 버전과의 하위 호환성을 보장하면서 최신 기능을 앱에 사용할 수 있습니다.
주요 기능
- UI 컴포넌트 하위 호환성
AppCompat 라이브러리는 FragmentActivity를 확장하고 하위 버전의 안드로이드와의
호환성을 보장하는 AppCompatActivity와 같은 최신 UI 컴포넌트를 제공합니다 - Material Design 지원
AppCompat을 사용하면 개발자는 하위 안드로이드 버전을 실행하는 기기에
Material Design 원칙을 통합할 수 있습니다. - 테마 및 스타일링 지원
- 동적 기능 지원
AppCompat을 사용하는 이유
AppCompat 라이브러리를 사용하는 주된 이유는 최신 안드로이드 기능과
UI 컴포넌트가 지원되는 모든 API 레벨에서 일관되게 작동하도록 보장하는 것입니다.
'Study' 카테고리의 다른 글
| 안드로이드 면접 북 스터디 Q60 ~ Q66 (0) | 2025.10.23 |
|---|---|
| 안드로이드 면접 북 스터디 Q50 ~ Q59 (0) | 2025.10.20 |
| 안드로이드 면접 북 스터디 Q30 ~ Q39 (0) | 2025.10.13 |
| 안드로이드 면접 북 스터디 Q20 ~ Q29 (3) | 2025.08.16 |
| 안드로이드 면접 북 스터디 Q10 ~ Q19 (4) | 2025.08.09 |